如何使用Swift中的约束来动画UIView?

nai*_*per 43 uiviewanimation ios swift xcode6

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

在此输入图像描述

如您所见,它包含一些简单的约束:

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

我想要实现的是让这个红色/粉红色的视图从顶部"进入".传统上,在一个无约束的世界中,我只是修改内部的框架UIView.animateWithDuration,但是我不确定我是如何在约束世界中做类似的.

为了重申我的问题,如何让我的视图从场景开始并使从顶部飞入的视图动画?

我已经考虑过制作垂直中心约束(并随后调用layoutIfNeeded),但它没有达到预期的效果.

谢谢你的帮助.

gab*_*ler 69

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

self.centerYConstraint.constant = 500.0
self.view.layoutIfNeeded()

UIView.animateWithDuration(Double(0.5), animations: {
        self.centerYConstraint.constant = 0
        self.view.layoutIfNeeded()
    })
Run Code Online (Sandbox Code Playgroud)

  • 伙计们,self.view.layoutIfNeeded()是关键 (15认同)

Dan*_*sko 14

你想要的实际上相当简单,我将详细说明如何在不搞乱优先级或时髦常数的情况下完成它.通过这种方式,我们可以获得适用于任何屏幕尺寸的动画.

TL; DR是您需要配置约束,然后在动画块内调用layoutIfNeeded来为更改设置动画.欲了解更多,请参阅此SO帖子.

因此,我们需要两组约束来隐藏和显示视图.在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)
}
Run Code Online (Sandbox Code Playgroud)

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

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)
}
Run Code Online (Sandbox Code Playgroud)

显示

同样,我们的show约束会将视图的中心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)
}
Run Code Online (Sandbox Code Playgroud)

便利方法

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

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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

func isRedViewVisible() -> Bool {
    return CGRectContainsPoint(self.view.bounds, self.redView.frame.origin)
}
Run Code Online (Sandbox Code Playgroud)


rin*_*aro 10

试试这个:

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()
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

在约束中要小心firstItemsecondItem排序.上面的代码假设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()
        }
    }

}
Run Code Online (Sandbox Code Playgroud)


Mas*_*eni 7

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

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

原因是对于向上滑动动画,您需要先将视图移出屏幕,然后将其恢复到原始位置.所以在你的viewDidLoad中只需使用:

yourView.transform = CGAffineTransformMakeTranslation(0, 500)
Run Code Online (Sandbox Code Playgroud)

这会将视图移出屏幕,在本例中位于底部.现在在 viewDidAppear中,您可以显示您的视图:

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

使用这些行,您可以在UIView上添加所需的约束,并将其放在ViewController中所需的位置.


Yan*_*eph 5

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

self.constraint.constant = -150

UIView.animate(withDuration: 0.45) { [weak self] in
    self?.view.layoutIfNeeded()
}
Run Code Online (Sandbox Code Playgroud)