CABasicAnimation
背景
展示个提示,像跑马灯. 最近要做这样的事情。乍一看,简单,但是:
做法
跑马灯,本质上就是一个位移动画,那自然是CABasicAnimation 和它的封装UIView.animate,本文主要看看CABasicAnimation
首先指定需要动画的属性
let positionAnimation = CABasicAnimation(keyPath:"position.x")
然后设置起始值和终止值
positionAnimation.fromValue = 0
positionAnimation.toValue = -leftOffset
最后是设置时间将动画加到label上
positionAnimation.duration = duration
label.layer.add(positionAnimation, forKey: animKey)
跑起来,发现看到的效果总是不对。文字并不是从制定的位置开始运动的
找问题
既然是看到的效果不对,那就看看负责显示动画的presentation layer层的位置是什么样子的
我们在每次执行动画前打印看一下:
label.layer.presentation()?.frame, 这是它的presentationLayer的frame
多次运行动画得到如下结果
rame: Optional((0.0, 0.0, 23.0, 9.0))
frame: Optional((-337.5139744877815, 0.0, 525.0, 9.0))
frame: Optional((-270.14062067866325, 0.0, 433.0, 9.0))
frame: Optional((-510.49657133221626, 0.0, 751.0, 9.0))
frame: Optional((-306.79565209150314, 0.0, 525.0, 9.0))
frame: Optional((-235.69693331420422, 0.0, 433.0, 9.0))
frame: Optional((-403.153050519526, 0.0, 751.0, 9.0))
frame: Optional((-282.75428069382906, 0.0, 525.0, 9.0))
frame: Optional((-177.64594815671444, 0.0, 341.0, 9.0))
frame: Optional((-236.20260278880596, 0.0, 433.0, 9.0))
frame: Optional((-462.53013302385807, 0.0, 751.0, 9.0))
可以看到当动画开始的时候负责显示的presentation layer的位置并不是0,这样处理的结果是,每次我们的跑马灯都是从左侧很远的地方开始滚动,不是我们想要的效果
自然我的第一个想法:就是开始动画前把动画都移除掉
positionAnimation.fillMode = .forwards
label.layer.removeAllAnimations()
但是发现不行,动画依然是从label中间某个位置开始运动
于是猜想是每次动画开始时label的实际的位置不对,我开始修改每次的起始位置,每次动画前手动将label的位置置为0,每次结束后,将label的位置复原;还找是不是每次动画还没有结束就开始新动画导致动画叠加导致的.然而都没有得到正确结果。
怎么办,只能看看现有的跑马灯是怎么做的,于是我在之前大神写的代码里发现了某个和我一样(比我高级多了的代码)里发现了跑马灯
发现转机
代码中是使用这样的方式:
将动画的kaypath变为transform.translation:
CABasicAnimation(keyPath:"transform.translation")
这个时候,我们需要将fromValue 和toValue都设置成 NSValue对象,对象里包含的是一个NSSize 或者 CGSize 的数据类型.用来表示x 和 y 坐标轴的转换.
同样,我们两个维度的变换可以变成一个维度的,也就是说keyPath设置成transform.translation.x也行。只是对应的fromValue 和toValue 设置成NSNumber对象。
毕竟是大神,用这样的代码,动画正常了,每次都从最左侧开始运动了。
这两种方式下每次启动动画的时候也不需要移除之前的动画。例如不需要以下的代码
label.layer.removeAllAnimations()
当然因为是跑马灯所以填充模式和是否移除这两句话也不需要了
animation.fillMode = .forwards
animation.isRemovedOnCompletion = false
原因
话说回来: position.x 和transform.translation有什么区别
参考官方文档
CATransform3D Key Paths
You can use the enhanced key path support to retrieve specific transformation values for a property that contains a CATransform3D data type. To specify the full key path for a layer’s transforms, you would use the string value transform or sublayerTransform followed by one of the field key paths in Table C-2. For example, to specify a rotation factor around the layer’s z axis, you would specify the key path transform.rotation.z.
CGPoint Key Paths
If the value of a given property is a CGPoint data type, you can append one of the field names in Table C-3 to the property to get or set that value. For example, to change the x component of a layer’s position property, you could write to the key path position.x.
对于我的整个label的运动来说,动画是加在layer层的,我的位移用的也是整个frame的位移,不是一个点。所以应该使用translation来指定动画的属性