以编程方式添加后,使用约束动画UIView

时间:2017-02-24 20:09:25

标签: ios animation constraints

我有一个UIView,我以编程方式添加到我的UIViewController中,如下所示:

if let myView = Bundle.main.loadNibNamed("MyView", owner: self, options: nil)?.first as? MyView
    {
        self.view.addSubview(myView)
        myView.translatesAutoresizingMaskIntoConstraints = false
        //Horizontal orientation
        self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":myView]))
    }

很好,在视图控制器的(0,0)处左右两侧添加了所需的空间。

我想要实现的是视图从视图控制器的底部动画到中心,然后从中心到顶部进行动画制作。 首先,我试图将它设置为动画,使其位于当前位置(0,0)

的中心位置

所以我做的是:

UIView.animate(withDuration: 1.0,
                   animations:
    {
        let center = NSLayoutConstraint(item: myView, attribute: .centerY, relatedBy: .equal, toItem: self.view, attribute: .centerY, multiplier: 1, constant: CGFloat(0.0))
        self.view.addConstraint(center)
    })

视图位于中心,但不是动画。它直接跳到它。

我搜索并找到了很多答案,说我必须设置约束的常量,然后调用layoutIfNeeded()但是所有这些示例都使用对之前设置为IBOutlet的约束的引用,我不这样做我以编程方式添加视图。

如何正确地为视图设置动画,从底部到中心然后从中心到顶部?

谢谢你!

问候

编辑1

好的,我会更进一步解释我想要实现的目标。 在我的视图控制器上,在向用户显示5秒计时器后,我想一个接一个地显示几个问题。

我想要一个问题从下到中滑入,已经回答,然后从中心向上滑动。然后,下一个问题从下到中,从幻灯片中回答,等等。

因此,在5秒计时器之后,我调用名为slideInQuestion的方法创建一个问题并将其设置为动画:

func slideInQuestion()
{
    let question:QuestionView = createQuestion()
    UIView.animate(withDuration: 1.0,
                   animations:
    {
        self.yConstraint?.constant = CGFloat(0.0)
        self.view.layoutIfNeeded()
    })

createQuestion方法实例化问题视图并为其分配约束

func createQuestion() -> QuestionView
{
    if let questionView = Bundle.main.loadNibNamed("QuestionView", owner: self, options: nil)?.first as? QuestionView
    {
        self.view.addSubview(questionView)
        questionView.translatesAutoresizingMaskIntoConstraints = false
        //Horizontal orientation
        self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":questionView]))
        yConstraint = NSLayoutConstraint(item: questionView,
                                              attribute: .centerY,
                                              relatedBy: .equal,
                                              toItem: self.view,
                                              attribute: .centerY,
                                              multiplier: 1,
                                              constant: CGFloat(UIScreen.main.bounds.height))
        self.view.addConstraint(yConstraint!)
        return questionView
    }
    return QuestionView()
}

之前,我将yConstraint定义为Duncan C建议的实例变量,如下所示:

    var yConstraint:NSLayoutConstraint?

所以我现在所期待的是:

创建问题视图,它的中心位于视图控制器的中心+屏幕的高度。这使它在屏幕底部的可见视图之外。然后它在1秒内从此位置滑动到屏幕的中心Y(0.0)。

但是它现在做的是从屏幕顶部滑动到屏幕的中心Y,同时它也会像在第一个约束中设置一样调整到左右边距

self.view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":questionView]))

我现在完全糊涂了,我希望我的解释有所帮助,而且有人有想法。

谢谢!

3 个答案:

答案 0 :(得分:3)

由于我不知道您的视图是如何从您的软件包中创建的,因此我已根据您的代码将一个快速示例合并到一起。

关键是self.view.layoutIfNeeded()被调用两次。一旦添加了视图,第二次在动画块中。并且约束的修改不在动画块内。

import UIKit

class ViewController: UIViewController {

    var yConstraint:NSLayoutConstraint?

    override func viewWillAppear(_ animated: Bool) {

        self.createView()

        self.view.layoutIfNeeded()

        self.yConstraint?.constant = 32
        UIView.animate(withDuration: 1.0) {
            self.view.layoutIfNeeded()
        }

    }

    func createView(){

        let questionView = UIView()
        questionView.backgroundColor = UIColor.red

        let heightConstraint = NSLayoutConstraint(item: questionView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .height, multiplier: 1, constant: self.view.bounds.height-64)
        questionView.addConstraint(heightConstraint)

        self.view.addSubview(questionView)

        questionView.translatesAutoresizingMaskIntoConstraints = false

        //Horizontal orientation
        self.view.addConstraints(
            NSLayoutConstraint.constraints(withVisualFormat: "H:|-10-[view]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: ["view":questionView]))

        yConstraint = NSLayoutConstraint(item: questionView,
                                         attribute: .top,
                                         relatedBy: .equal,
                                         toItem: self.view,
                                         attribute: .top,
                                         multiplier: 1,
                                         constant: CGFloat(UIScreen.main.bounds.height))
        self.view.addConstraint(yConstraint!)
    }
}

答案 1 :(得分:1)

创建约束并将其保存在实例变量中。然后,当您想要为其设置动画时,更改约束上的常量并从动画块调用layoutIfNeeded,就像为动画基于故事板的约束设置动画一样。

在您的情况下,请勿在您的功能中使用let constraint = ...。相反,使用:

var centerConstraint: NSLayoutConstraint?

在viewWillAppear中:

centerConstraint = NSLayoutConstraint(item: myView, 
  attribute: .centerY, 
  relatedBy: .equal, 
  toItem: self.view, 
  attribute: .centerY,  
  multiplier: 1,  
  constant: CGFloat(0.0))
self.view.addConstraint(center)

当你想要动画时:

UIView.animate(withDuration: 1.0,
                   animations:
    {
       centerConstraint.constant = newValue  //(Your value here.)
       myView.layoutIfNeeded()
    })

答案 2 :(得分:0)

首先声明一个骗子

var constraintName: NSLayoutConstraint?

viewWillAppear()

constraintName = NSLayoutConstraint(item: animateView,
                                          attribute: .centerX,
                                          relatedBy: .equal,
                                          toItem: self.view,
                                          attribute: .centerX,
                                          multiplier: 1,
                                          constant: CGFloat(0.0))
    self.view.addConstraint(constraintName!)


    UIView.animate(withDuration: 0.0) {
        self.constraintName?.constant -= constantSize e.g. 200
        self.animateView.layoutIfNeeded()

    }

所有设置。