ios 如何在 Swift 中为带有约束的 UIView 设置动画?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27371935/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 03:57:24  来源:igfitidea点击:

How to animate a UIView with constraints in Swift?

iosswiftxcode6uiviewanimation

提问by naivedeveloper

In my contrived example, I have the following single view:

在我人为的示例中,我有以下单一视图:

enter image description here

在此处输入图片说明

As you can see, it consists of a few simple constraints:

如您所见,它由一些简单的约束组成:

  1. Align horizontal and vertical centers,
  2. Height (set to a constant)
  3. Leading and trailing spaces (set to constant)
  1. 对齐水平和垂直中心,
  2. 高度(设置为常数)
  3. 前导和尾随空格(设置为常量)

What I'm seeking to achieve is to have this redish/pinkish view "come in" from the top. Traditionally, in a constraint-less world, I would simply modify the frame inside of UIView.animateWithDuration, however I'm not sure how I do the similar in a constraint world.

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

To reiterate my question, how can I make my view start out of scene and animate the view flying in from the top?

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

I've considered animating the vertical centers constraint (and subsequently calling layoutIfNeeded), but it's not achieving the desired effect.

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

Thanks for your help.

谢谢你的帮助。

回答by gabbler

What you can do is to add the following code in your viewDidAppearmethod. You firstly make a IBOutletproperty of your view's center Y constraint, and then change its constant value.

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

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

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

回答by Daniel Galasko

What you want is in fact rather simple, and I will detail how it should be done without messing with priorities or funky constants. This way we can get an animation that will work on any screen size.

你想要的实际上相当简单,我将详细说明如何在不影响优先级或时髦常量的情况下完成它。这样我们就可以得到一个可以在任何屏幕尺寸上工作的动画。

The TL;DR is that you need to configure your constraints and then call layoutIfNeeded inside your animation block to animate the changes. For more see this SO post.

TL;DR 是您需要配置约束,然后在动画块内调用 layoutIfNeeded 来为更改设置动画。有关更多信息,请参阅此 SO 帖子

So we need two sets of constraints for hiding and showing the view. In viewDidLoadthe view will be hidden, and then in viewDidAppearor wherever we want that view to slide in.

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

Storyboard/XIB Setup

故事板/XIB 设置

So the first thing is to configure the constraints that won't be changing in IB (or code, whichever you are comfortable with). Namely; the height of the red view, and its leading and trailing space to the container. So your constraints might look like this (note:I haven't set a width constraint but let the leading and trailing spaces define the width):

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

Constraints

约束

Now you will see that IB will warn you that there is no constraint configured for the Y position of your view (hence the red dotted lines)

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

View with warnings

查看有警告

You can now add the top space to container constraint and set it as a placeholder constraint (checkbox that says "remove at build time"). We do this because we want to control where the view is programatically.

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

enter image description here

在此处输入图片说明

This means that this constraint will not exist once the view is loaded but serves to remove all your warnings as you are telling IB that you know how to deal with this constraint when the view is loaded.

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

Coding Time

编码时间

Now we need a method to hide the view, a method to show the view. For this we are going to store the Y positioning constraint on the view and then animate it. Our viewController could look like this:

现在我们需要一个隐藏视图的方法,一个显示视图的方法。为此,我们将在视图上存储 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)
}

Hiding

隐藏

Our method to hide the view can simply remove the position constraint and then add one with the red views bottom equal to the view controller's view top:

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

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

Showing

显示

Similarly our show constraint will move the view's center Y to the controllers center Y:

类似地,我们的 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)
}

Convenience Methods

方便的方法

For completeness the convenience methods I have used look like this:

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

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

You can also check if the red view is visible by using some CGRect math:

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

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

回答by rintaro

Try this:

尝试这个:

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

}

Be careful about firstItemand secondItemorder in the constraint. The above code assumes Superview is the firstItem:

小心firstItemsecondItem在约束中排序。上面的代码假设 Superview 是firstItem

screenshot

截屏



Alternative way is to define twoconstraints:

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

  • Center Y Alignment constraint(Superview.CenterY == View.CenterY) priority = 750
  • Vertical Space Constraint(SuperView.Top == View.Bottom) priority = 500
  • 中心 Y 对齐约束(Superview.CenterY == View.CenterY) 优先级 = 750
  • 垂直空间约束(SuperView.Top == View.Bottom)优先级 = 500

screenshot

截屏

And adjust the priorityto determine which contraint should be adopted.

并调整优先级来确定应该采用哪种约束。

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

}

回答by Massimo Polimeni

For anyone looking for simple animation like the request:

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

For the slide up animation you need to use [...] the CGAffineTransformMakeTranslation(x, y).

The reason is that for a slide up animation you need first move the view off screen and then bring it back to its original position. So in your viewDidLoad just use:

yourView.transform = CGAffineTransformMakeTranslation(0, 500)

This moves the view off screen, in this case at the bottom. Now in the viewDidAppearyou can show your view with:

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

对于向上滑动动画,您需要使用 [...] 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)

With these lines you can add the constraints that you want on your UIView and place it where you need in your ViewController.

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

回答by YannSteph

For me the best way for animate Swift 3 & 4

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

self.constraint.constant = -150

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