2017-02-24 52 views
2

加入后,我有我编程方式添加到我的UIViewController像这样的的UIView:动画的UIView与约束它编程

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

但是,什么是正确的,现在,从屏幕顶部滑动到屏幕的centerY以及在它会调整到的边缘,同时做左,右像它在第一约束集

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

我完全困惑,现在我希望我的解释有帮助,有人有一个想法。

谢谢!

+0

为什么程序化与IBOutlet有关系?无论您想要如何设置您的预动画约束,然后设置您的后动画约束,然后在需要更改时在动画块内调用“layoutIfNeeded”。 – Connor

回答

1

由于我不知道你的观点是从你的包创建的,我已经根据您的代码入侵了一个快速示例。

关键是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!) 
    } 
} 
+0

谢谢!确实问题是我不得不两次调用layoutIfNeeded。将视图添加到控制器后,然后添加到动画块中。 今天学到了东西,谢谢! –

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

谢谢,是的,你说的对,昨天已经晚了。 事实上,我可以将约束存储在一个变量中。 但我仍然有问题。我必须添加多个评论,否则我没有足够的角色来解释,对不起。 –

+0

我把我的约束像 yConstraint = NSLayoutConstraint(项目:MyView的, 属性:.centerY, relatedBy:.equal, toItem:self.view, 属性:.centerY, 乘数:1, 常数:CGFloat的( !UIScreen.main.bounds.height)) self.view.addConstraint(yConstraint) –

+0

和更新一样 UIView.animate(withDuration:1.0, 动画: { self.yConstraint .constant = CGFloat的(0.0) () }) 但是,它从顶部滑入,为什么?并不是独一无二的,它还可以调整我设置的第一个约束的左右边界的大小(您可以在第一个帖子中看到它,即将页边距保持在左右的那个)。 我很抱歉,我越想越感到困惑。 在myView上调用layoutIfNeeded而不是self.view不起作用,它只从左右调整 –