观察动画期间UIView的帧变化

时间:2014-03-22 19:07:18

标签: ios animation uiview observer-pattern

我希望观察UIView原点的x坐标在使用animateWithDuration:delay:options:animations:completion:进行动画处理时的变化。我希望在此动画期间以粒度级别跟踪x坐标中的更改,因为我希望在与要动画的视图可能与之接触的另一个视图的交互中进行更改。我想在确切的联系点做出改变。我想了解在更高层次上做这样的事情的最佳方式:

- 我应该在联系人的完成回拨中使用animateWithDuration:...吗?换句话说,第一个动画一直运行直到它到达那个x坐标,动画的其余部分发生在完成回调中?

- 我应该使用NSNotification观察者并观察对帧属性的更改吗?这有多准确/精细?我可以跟踪x的每个变化吗?我应该在一个单独的线程中这样做吗?

欢迎任何其他建议。我正在寻找一种开始练习。

3 个答案:

答案 0 :(得分:12)

使用CADisplayLink,因为它是专门为此目的而构建的。在文档中,它说:

  

一旦显示链接与运行循环相关联,当需要更新屏幕内容时,将调用目标上的选择器。

对我来说,我有一个填满的酒吧,当它通过某个标记时,我不得不改变该标记上方的视图颜色。

这就是我所做的:

let displayLink = CADisplayLink(target: self, selector: #selector(animationDidUpdate))
displayLink.frameInterval = 3
displayLink.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSDefaultRunLoopMode)

UIView.animateWithDuration(1.2, delay: 0.0, options: [.CurveEaseInOut], animations: { 
    self.viewGaugeGraph.frame.size.width = self.graphWidth
    self.imageViewGraphCoin.center.x = self.graphWidth
    }, completion: { (_) in
        displayLink.invalidate()
})

func animationDidUpdate(displayLink: CADisplayLink) {
    let presentationLayer = self.viewGaugeGraph.layer.presentationLayer() as! CALayer

    let newWidth = presentationLayer.bounds.width

    switch newWidth {
    case 0 ..< width * 0.3: 
        break
    case width * 0.3 ..< width * 0.6: 
        // Color first mark
        break 
    case width * 0.6 ..< width * 0.9:
        // Color second mark
        break
    case width * 0.9 ... width:
        // Color third mark
        break
    default:
        fatalError("Invalid value observed. \(newWidth) cannot be bigger than \(width).")
    }
}

在示例中,我将frameInterval属性设置为3,因为我没有必要严格更新。默认值为1,这意味着它将针对每一帧进行触发,但这会对性能造成影响。

答案 1 :(得分:7)

创建一个NSTimer有一些延迟,并在每次失效后运行特定的选择器。
在该方法中,检查动画视图的框架并将其与碰撞视图进行比较。

并确保使用 presentationLayer frame ,因为如果您在制作动画时访问view.frame,它会在动画中提供不变的目标帧。

CGRect animationViewFrame= [[animationView.layer presentationLayer] frame];

如果你不想创建计时器,write a selector which calls itself after some delay。延迟大约.01秒。

<强>澄清 - &GT;
假设您有一个视图,您可以将其位置从(0,0)设置为(100,100),持续时间为5秒。假设您已将KVO实施到此视图的框架中

当您调用animateWithDuration block时,即使视图以中间位置值移动,视图的位置也会将直接更改为(100,100),这是最终值。

因此,您的 KVO将在动画开始时被解雇一次。 因为,图层有layer TreePresentation Tree。虽然layer tree只存储目标值,而presentation Layer存储中间值。
当您访问view.frame时,它将始终在layer tree中提供帧的值,而不是它所采用的中间帧。

因此,您必须使用presentation Layer frame来获取中间帧。

希望这有帮助。

答案 2 :(得分:1)

UIDynamics和碰撞行为在这里值得研究。您可以设置发生冲突时调用的委托。

有关详细信息,请参阅collision behaviour documentation