任意值动画的平滑需求
在上文利用SubLayer完成线性动画中我们提到了可以使用SubLayer完成线性动画,主要的好处是
- 不用手动去处理动画PresentTree的控制(避免闪烁)
- 不用考虑动画的中间状态(不用考虑动画过程)
以下是一个相机Capture按键的的需求
用户操作 | 动画状态 |
---|---|
按下Press | 按键缩小 |
未抬起Hold | 按键缩小到最小值保持尺寸 |
抬起Trick | 按键放大,并且开始Loading动画 |
拍摄Loading | 按键尺寸在最大和最小值之间过度 |
拍摄完成 | 无论按键处于哪个过程,马上返回原始尺寸 |
平滑动画面临的问题
这里最难处理的就是,在拍摄完成时,按键的动画 有可能处于 大—>小 也有可能处于 小—>大 这里需要根据当前的Present Tree处于哪个过程来决定
- 大—>小: 此时需要马上停止动画,返回最大的尺寸
- 小—>大: 此时需要继续执行动画到最大尺寸
如果采用雷达动画中的Property Animation 我们很难去界定动画的 fromValue
根据Property的动画原理可以知道当前的显示由PresentTree决定,网上的回答都提到了该方法
- CABasicAnimation start from current layer position
- Cannot get current position of CALayer during animation
但是上文也提到了两个不可避免的问题
- 通过 PresentLayer 拿到当前的显示值很难准确定位
- 如何控制剩余的动画时间
根据面临的问题下文给出 CATransaction解决方案 以及 失败的 Property的尝试
创建一个自定义的控件
函数 | 目的 |
---|---|
touchesBegan | 在开始触摸时进入hold状态 |
touchesEnded | 在触摸结束时,进入摄像状态,并且尝试返回normal状态 |
interrupt | 无论动画处于何种状态,都打断动画返回normal状态 |
1 | class CaptureButton: UIControl { |
CATransaction解决方案
根据文章隐式动画的原理,注意completion的书写顺序,可以完成两个状态的动画控制 对比Property动画明显可以发现控制逻辑更加简单
1 | class CaptureLayer: CALayer { |
Property的尝试(失败,如果谁能找到解决方法希望留言)
使用Property动画我们明显可以发现,由于AnimateGroup的创建,我们明显需要更多的代码来控制逻辑
并且在 interrupt 函数触发时,很难控制动画的闪烁效果
1 | class CaptureProperty: UIControl, CAAnimationDelegate { |