【问题标题】:How to animate a UIView with constraints in Swift?如何在 Swift 中为带有约束的 UIView 设置动画?
【发布时间】:2015-02-06 22:21:16
【问题描述】:

在我设计的示例中,我有以下单一视图:

如您所见,它由几个简单的约束组成:

  1. 水平和垂直中心对齐,
  2. 高度(设置为常数)
  3. 前导和尾随空格(设置为常量)

我想要实现的是让这种带红色/粉红色的视图从顶部“进来”。传统上,在无约束的世界中,我会简单地修改UIView.animateWithDuration 内的框架,但是我不确定在约束世界中我如何做类似的事情。

重申我的问题,我怎样才能让我的视图从场景开始并动画从顶部飞入的视图?

我考虑过为垂直中心约束设置动画(随后调用layoutIfNeeded),但没有达到预期的效果。

感谢您的帮助。

【问题讨论】:

标签: ios swift xcode6 uiviewanimation


【解决方案1】:

对于任何寻找像请求这样的简单动画的人:

对于上滑动画,您需要使用 [...] CGAffineTransformMakeTranslation(x, y)。

原因是,对于上滑动画,您需要先将 查看屏幕,然后将其恢复到原始位置。所以在 您的 viewDidLoad 只需使用:

yourView.transform = CGAffineTransformMakeTranslation(0, 500)

这会将视图移出屏幕,在本例中位于底部。现在在 viewDidAppear 您可以通过以下方式展示您的视图:

UIView.animateWithDuration(0.7, delay: 0.0, usingSpringWithDamping: 0.5,
initialSpringVelocity: 0.5, options: [], animations: {
        self.yourView.transform = CGAffineTransformMakeScale(1, 1)
    }, completion: nil)

通过这些行,您可以在 UIView 上添加所需的约束并将其放置在 ViewController 中您需要的位置。

【讨论】:

  • 你能从你的链接中添加一些内容吗?
  • 请等几分钟!
  • 这个动画不错
【解决方案2】:

对我来说,制作动画的最佳方式 Swift 3 & 4

self.constraint.constant = -150

UIView.animate(withDuration: 0.45) { [weak self] in
    self?.view.layoutIfNeeded()
}

【讨论】:

    【解决方案3】:

    你想要的其实很简单,我将详细说明应该如何完成它,而不会弄乱优先级或时髦的常量。这样我们就可以获得适用于任何屏幕尺寸的动画。

    TL;DR 是您需要配置约束,然后在动画块内调用 layoutIfNeeded 以动画化更改。更多see this SO post.

    所以我们需要两组约束来隐藏和显示视图。在viewDidLoad 中,视图将被隐藏,然后在viewDidAppear 或我们希望该视图滑入的任何位置。

    故事板/XIB 设置

    所以第一件事是配置在 IB 中不会改变的约束(或代码,无论你喜欢哪个)。即;红色视图的高度,以及它到容器的前导和尾随空间。所以你的约束可能看起来像这样(注意:我没有设置宽度约束,但让前导和尾随空格定义宽度):

    现在您将看到 IB 会警告您没有为视图的 Y 位置配置约束(因此是红色虚线)

    您现在可以将顶部空间添加到容器约束并将其设置为占位符约束(显示“在构建时删除”的复选框)。我们这样做是因为我们想以编程方式控制视图的位置。

    这意味着一旦加载视图,此约束将不存在,但用于删除所有警告,因为您告诉 IB 您知道如何在加载视图时处理此约束。

    编码时间

    现在我们需要一个隐藏视图的方法,一个显示视图的方法。为此,我们将在视图上存储 Y 定位约束,然后对其进行动画处理。我们的 viewController 可能如下所示:

    @IBOutlet weak var redView: UIView!
    var redViewYPositionConstraint: NSLayoutConstraint?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.hideRedViewAnimated(false)
    }
    
    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.showRedViewAnimated(true)
    }
    

    隐藏

    我们隐藏视图的方法可以简单地移除位置约束,然后添加一个红色视图底部等于视图控制器的视图顶部:

    func hideRedViewAnimated(animated: Bool) {
        //remove current constraint
        self.removeRedViewYPositionConstraint()
        let hideConstraint = NSLayoutConstraint(item: self.redView,
            attribute: .Bottom,
            relatedBy: .Equal,
            toItem: self.view,
            attribute: .Top,
            multiplier: 1,
            constant: 0)
        self.redViewYPositionConstraint = hideConstraint
        self.view.addConstraint(hideConstraint)
        //animate changes
        self.performConstraintLayout(animated: animated)
    }
    

    显示

    同样,我们的显示约束将视图的中心 Y 移动到控制器中心 Y:

    func showRedViewAnimated(animated: Bool) {
        //remove current constraint
        self.removeRedViewYPositionConstraint()
        let centerYConstraint = NSLayoutConstraint(item: self.redView,
            attribute: .CenterY,
            relatedBy: .Equal,
            toItem: self.view,
            attribute: .CenterY,
            multiplier: 1,
            constant: 0)
        self.redViewYPositionConstraint = centerYConstraint
        self.view.addConstraint(centerYConstraint)
        //animate changes
        self.performConstraintLayout(animated: animated)
    }
    

    便捷方法

    为了完整起见,我使用的便捷方法如下所示:

    func performConstraintLayout(animated animated: Bool) {
        if animated == true {
              UIView.animateWithDuration(1,
              delay: 0,
              usingSpringWithDamping: 0.5,
              initialSpringVelocity: 0.6,
              options: .BeginFromCurrentState,
              animations: { () -> Void in
                 self.view.layoutIfNeeded()
              }, completion: nil)
         } else {
              self.view.layoutIfNeeded()
         }
    }
    
    func removeRedViewYPositionConstraint() {
        if redViewYPositionConstraint != nil {
            self.view.removeConstraint(self.redViewYPositionConstraint!)
            self.redViewYPositionConstraint = nil
        }
    }
    

    您还可以使用一些 CGRect 数学检查红色视图是否可见:

    func isRedViewVisible() -> Bool {
        return CGRectContainsPoint(self.view.bounds, self.redView.frame.origin)
    }
    

    【讨论】:

      【解决方案4】:

      试试这个:

      class ViewController: UIViewController {
      
          // red view
          @IBOutlet weak var myView: UIView!
          //  vertical align contraint
          @IBOutlet weak var verticalConstraint: NSLayoutConstraint!
      
          override func viewDidLoad() {
              super.viewDidLoad()
              verticalConstraint.constant = (myView.bounds.height + self.view.bounds.height)/2
          }
      
          override func viewDidAppear(animated: Bool) {
              super.viewDidAppear(animated)
              self.view.layoutIfNeeded()
              UIView.animateWithDuration(0.5) {
                  self.verticalConstraint.constant = 0
                  self.view.layoutIfNeeded()
              }
          }
      
      }
      

      注意约束中的firstItem 和secondItem 顺序。上面的代码假设 Superview 是firstItem:


      另一种方法是定义两个约束:

      • 中心 Y 对齐约束 (Superview.CenterY == View.CenterY) 优先级 = 750
      • 垂直空间约束 (SuperView.Top == View.Bottom) 优先级 = 500

      并调整优先级以确定应采用哪个约束。

      class ViewController: UIViewController {
      
          //  vertical align contraint
          @IBOutlet weak var centerYConstraint: NSLayoutConstraint!
      
          override func viewDidLoad() {
              super.viewDidLoad()
              centerYConstraint.priority = 250
          }
      
          override func viewDidAppear(animated: Bool) {
              super.viewDidAppear(animated)
              self.view.layoutIfNeeded()
              UIView.animateWithDuration(0.5) {
                  self.centerYConstraint.priority = 750
                  self.view.layoutIfNeeded()
              }
          }
      
      }
      

      【讨论】:

      • 优先级严格来说并不是实现这一目标的最佳方法,因为您希望布局系统不会因为其较低的优先级而强制执行中心约束。您应该正确配置约束以隐藏和显示视图
      【解决方案5】:

      您可以做的是在您的viewDidAppear 方法中添加以下代码。您首先为视图的中心 Y 约束创建一个 IBOutlet 属性,然后更改其常量值。

      self.centerYConstraint.constant = 500.0
      self.view.layoutIfNeeded()
      
      UIView.animateWithDuration(Double(0.5), animations: {
              self.centerYConstraint.constant = 0
              self.view.layoutIfNeeded()
          })
      

      【讨论】:

      • 使用常量并不意味着您已经将视图居中。如果您旋转设备,您将失去视线。
      • 各位,self.view.layoutIfNeeded() 是关键
      • @DanielGalasko,您可以反转第一项和第二项以从 -500 变为 0
      • @wyu 不完全确定我的意思是否有意义?我已经回答了这个问题stackoverflow.com/a/27417189/1652402
      • 好的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-11
      • 1970-01-01
      • 2016-11-29
      • 2021-06-23
      • 2019-09-02
      • 1970-01-01
      相关资源
      最近更新 更多