2017-06-03 34 views
2

我在网上找到的所有示例UIViewPropertyAnimator都使用通过设置框架而不是使用自动布局来布置的视图,而视图通常是如何布置的。当使用自动布局时,视图会动画到我想要的位置,但之后我不确定如何将其设置回“模型”位置。如何在自动布局中使用UIViewPropertyAnimator?

// Move a view that is constrained to the center of its superview 
UIViewPropertyAnimator(duration: 1, curve: .linear) { 
    testView.center = CGPoint(x: 10, y: 10) 
}.startAnimation() 

它显然增加了某种约束?我在执行动画之前和之后记录了容器视图的约束:

CONSTRAINTS BEFORE: 
view: [<NSLayoutConstraint:0x618000094f00 UIView:0x7fd764004050.centerX == UIView:0x7fd75fd00000.centerX (active)>, <NSLayoutConstraint:0x618000092de0 UIView:0x7fd764004050.centerY == UIView:0x7fd75fd00000.centerY (active)>] 

CONSTRAINTS AFTER: 
view: [<NSLayoutConstraint:0x618000094f00 UIView:0x7fd764004050.centerX == UIView:0x7fd75fd00000.centerX (active)>, <NSLayoutConstraint:0x618000092de0 UIView:0x7fd764004050.centerY == UIView:0x7fd75fd00000.centerY (active)>, <NSLayoutConstraint:0x6100000922a0 'UIView-Encapsulated-Layout-Height' UIView:0x7fd75fd00000.height == 667 (active)>, <NSAutoresizingMaskLayoutConstraint:0x610000092570 h=-&- v=-&- 'UIView-Encapsulated-Layout-Left' UIView:0x7fd75fd00000.minX == 0 (active, names: '|':UIWindow:0x7fd75fc07110)>, <NSAutoresizingMaskLayoutConstraint:0x610000092890 h=-&- v=-&- 'UIView-Encapsulated-Layout-Top' UIView:0x7fd75fd00000.minY == 0 (active, names: '|':UIWindow:0x7fd75fc07110)>, <NSLayoutConstraint:0x610000091670 'UIView-Encapsulated-Layout-Width' UIView:0x7fd75fd00000.width == 375 (active)>] 

这是怎么回事?我应该如何处理使用自动布局定位的视图的动画?苹果是否鼓励用户回到基于帧的布局?

回答

7

您可以使用UIViewPropertyAnimator自动布局,但你需要修改,而不是视图的框架的限制,并呼吁layoutIfNeeded()封闭的内部。

第一个例子:通过修改约束constant

创建故事板的视图动画。创建一个约束来将视图的centerX定位为等于超视图的前沿。创建一个@IBOutlet到该约束并将其称为centerXConstraint。同样,创建一个centerYConstraint,将您的视图的centerY定位到其超级视图的顶部。这两个约束都应该有constant = 0

创建@IBOutlet s到约束:

@IBOutlet weak var centerXConstraint: NSLayoutConstraint! 
@IBOutlet weak var centerYConstraint: NSLayoutConstraint! 

设置约束的constant值到新的位置,然后调用view.layoutIfNeeded()UIViewPropertyAnimator内:

// Make sure view has been laid out 
view.layoutIfNeeded() 

// Set new X and Y locations for the view 
centerXConstraint.constant = 50 
centerYConstraint.constant = 80 

UIViewPropertyAnimator(duration: 1, curve: .easeInOut) {    
    self.view.layoutIfNeeded() 
}.startAnimation() 

第二个例子:通过激活新约束来动画

创建在故事板(例如redView)的图和在代码创建@IBOutlet它:

@IBOutlet weak var redView: UIView! 

创建@IBOutlet s至该控制视图的位置的约束

// Outlets to the constraints set in the Storyboard 
@IBOutlet weak var topConstraint: NSLayoutConstraint! 
@IBOutlet weak var leadingConstraint: NSLayoutConstraint! 

然后当它的动画时间:

// Make sure view has been laid out 
view.layoutIfNeeded() 

// Deactivate the old constraints 
topConstraint.isActive = false 
leadingConstraint.isActive = false 

// Active new constraints that move view to the bottom right   
redView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true 
redView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true 

// Animate the change   
UIViewPropertyAnimator(duration: 1, curve: .easeInOut) { 
    self.view.layoutIfNeeded() 
}.startAnimation() 

那么这是如何比旧的UIView动画块更好?

UIViewPropertyAnimator是一个对象,您可以配置该对象以各种方式控制动画。下面是展示一个完整的例子:

  1. 开始动画
  2. 暂停动画
  3. 找出已完成的动画部分和设置幻灯片值到
  4. 通过了动画清理与滑块

Scrubbing animation demo

class ViewController: UIViewController { 

    @IBOutlet weak var redView: UIView! 
    @IBOutlet weak var centerXConstraint: NSLayoutConstraint! 
    @IBOutlet weak var centerYConstraint: NSLayoutConstraint! 
    @IBOutlet weak var slider: UISlider! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     slider.isHidden = true 
    } 

    var myAnimator: UIViewPropertyAnimator? 

    @IBAction func startAnimation(_ sender: UIButton) { 
     view.layoutIfNeeded() 

     centerXConstraint.isActive = false 
     centerYConstraint.isActive = false 

     redView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true 

     redView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true 

     myAnimator = UIViewPropertyAnimator(duration: 10, curve: .easeInOut) { 

      self.view.layoutIfNeeded() 
     } 

     myAnimator?.startAnimation() 
    } 

    @IBAction func pauseAnimation(_ sender: UIButton) { 
     guard let myAnimator = myAnimator else { return } 

     myAnimator.pauseAnimation() 

     print("The animation is \(String(format: "%.1f", myAnimator.fractionComplete * 100))% complete") 

     slider.value = Float(myAnimator.fractionComplete) 
     slider.isHidden = false 
    } 

    @IBAction func scrub(_ sender: UISlider) { 
     myAnimator?.fractionComplete = CGFloat(sender.value) 
    } 
} 
+0

这与UIView动画块的旧方法相同。没有任何改善?那些生成的约束又是什么? – GoldenJoe

+0

UIViewPropertyAnimator是一个可以配置为允许动画暂停,反转等的对象。您可以创建自己的曲线来控制速度等等。 – vacawama

+0

我不明白你在问什么约束。我只是在演示如何将新约束应用于视图并对其进行动画处理。 – vacawama