一. CA类之间的关系
如图,
二. CAMediaTiming协议
该协议中, 提供了以下属性:
beginTime 用来设置动画延时,若想延迟1秒,就设置为CACurrentMediaTime()+1,其中CACurrentMediaTime()为图层当前时间。
duration 动画的持续时间。
speed 动画速率,决定动画时间的倍率。当speed为2时,动画时间为设置的duration的1/2。
timeOffset 动画时间偏移量。比如设置动画时长为3秒,当设置timeOffset为1.5时,当前动画会从中间位置开始,并在到达指定位置时,走完之前跳过的前半段动画。
repeatCount 动画的重复次数。
repeatDuration 动画的重复时间。
autoreverses 动画由初始值到最终值后,是否反过来回到初始值的动画, 默认为NO。如果设置为YES,就意味着动画完成后会以动画的形式回到初始值。
fillMode 决定当前对象在非动画时间段的行为.比如动画开始之前,动画结束之后。
⚠️:其实不只是CAAnimation遵循CAMediaTiming协议,熟悉底层结构的小伙伴们应该知道CALayer也遵循这个协议,所有在一定程度上我们可以通过控制layer本身的协议属性来控制动画节奏。
三. CAAnimation类
timingFunction 控制动画节奏, 枚举类型
delegate 指定CAAnimationDelegate的代理人,用于监听动画.
开始-(void)animationDidStart
结束-(void)animationDidStop(能监听动画的stop和remove)
removedOnCompletion 在动画完成后是否移除动画,默认为YES.
注意:,如果想保持动画执行后的状态, 需要设置removedOnCompletion为NO,并且设置fillMode为kCAFillModeForwards。但如此操作并不会改变layer实际的值, 更加推荐”动画结束后通过事务CATransaction关闭隐式动画,并set操作layer的值”
详情参考:https://www.jianshu.com/p/51483b560244
四.CAPropertyAnimation及其子类
1. 继承于CAAnimation, 一般直接使用其子类来操作动画,不使用本类.
类方法:
+ (instancetype)animationWithKeyPath:(nullable NSString *)path;
keyPath解析: CALayer的某个属性名,并通过这个属性的值进行修改,达到相应的动画效果.
至于keyPath的值,可以参考http://www.cnblogs.com/pengyingh/articles/2379631.html
或者参考:
opacity 透明度
backgroundColor 背景颜色
cornerRadius 圆角
borderWidth 边框宽度
contents 内容
…
rotation 旋转
transform.rotation.x
transform.rotation.y
…
scale 缩放
transform.scale.x
transform.scale.y
transform.scale.z
…
translation 平移
transform.translation.x
transform.translation.y
transform.translation.z
…
position 位置
position.x
position.y
…
bounds 大小
bounds.size.width
bounds.origin.x
… … 以及CALayer子类对应的各个属性(比如CAShapeLayer的path)
2.两个子类包括CABasicAnimation(基础动画)和CAKeyframeAnimation(关键帧动画), 下面接着讲解.
2.1 对于CABasinAnimation, 仅有三个属性:
fromValue, keyPath相应属性的初始值
toValue, keyPath相应属性的结束值
byValue, 在不设置toValue时,toValue = fromValue + byValue,也就是在当前的位置上增加多少
而CASpringAnimation ,继承于CABasinAnimation, 是带有初始速度以及阻尼指数等物理参数的属性动画。
我们可以把它看成在不绝对光滑的地面上,一个弹簧拴着别小球,那么我们可以这么理解他的属性:
mass -> 小球质量,影响惯性。
stiffness -> 弹簧的劲度系数。
damping -> 阻尼系数,地面的摩擦力。
initialVelocity -> 初始速度,相当于给小球一个初始速度(可正可负,方向不同)
settlingDuration -> 结算时间,根据上述参数计算出的预计时间,相对于你设置的时间,这个时间比较准确。
2.2 对于CAKeyframeAnimation ,同样通过keyPath对应属性进行控制,但它可以通过values或者path进行多个阶段的控制。
属性如下:
path 关键帧路径,优先级比values高,但是只对CALayer的anchorPoint和position起作用。
values 关键帧组成的数组,动画会依次显示其中的每一帧,如果设置了path,那么values将被忽略。
keyTimes 数组, 每一帧对应的时间,如果不设置,则各关键帧平分设定时间。
timingFunctions 数组 每一帧对应的动画节奏。
tensionValues -> 动画张力控制数组。
continuityValues -> 动画连续性控制数组。
biasValues -> 动画偏差率控制数组。
五. CATransition
是CAAnimation的子类,用于做转场动画,能够为层提供移出屏幕和移入屏幕的动画效果.
属性如下:
type -> 转场动画类型。
subtype -> 转场动画方向。
startProgress -> 动画起点进度(整体的百分比)。
endProgress -> 动画终点进度(整体的百分比)。
关于type的值:
六. CAAnimationGroup组合动画
/* An array of CAAnimation objects. Each member of the array will run
* concurrently(同时地,并发地) in the time space of the parent animation using the normal rules. */
@property(nullable, copy) NSArray *animations;
七.仿射变换CGAffineTransform
数学原理参考https://www.cnblogs.com/yulang314/p/5128661.html
变化原理:源视图上的点p(x,y)变化成目标视图中p’(x’,y’)。对应关系为:
注意:
CGAffineTransformIdentity, 获取本身的转换比例transform;
其次, 转换后, 动画会停留在最终状态, 参数值发生了实质变换.
1.平移变换
我们如果想要达到平移的目的,只需要x’ = x + tx,y’ = y + ty(改变对应点的横纵坐标的位置即可)。那么这样算来,仿射变换的参数中,a = 1,b = 0, c = 0, d = 1。也就是说,我们确定了四个参数,那么我们可以根据自己的需求给定tx,ty,这样就完成了平移的设置。
所以, ios还提供了这个函数用于平移:
CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty)
还有另外一个平移变换的构造:
CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty)
两者的区别当我们对一个视图进行平移操作的时候,前者每次都会从初始位置开始平移(操作前回到原来的位置),后者是从给定参数(通常是上一次的状态)的基础上继续平移。
2.缩放变换
缩放的操作,本质上是拉长或缩短了原来的点与点之间的距离,那么也就是说我们只需要让x’ = a * x, y’ = d *y(将一个点的横坐标和纵坐标放大或者缩小若干倍)。根据平移的经验,那么这样算来,仿射变换的参数中,b = 0, c = 0,tx = 0,ty = 0。也就是说,我们确定了四个参数,那么我们可以根据自己的需求给定a,b,这样就完成了缩放的设置,系统称变换的系数为sx,sy。
同样它有两种给定参数的方式:
CGAffineTransformMakeScale(CGFloat sx, CGFloat sy)
CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy)
前者依然是在视图初始状态的基础上进行缩放(每次缩放前都先回到初始状态),后者是在前一次操作后的基础上进行缩放操作。
3.旋转变换
在iOS中,视图的旋转是按照顺时针进行一个角度(假定为α)的改变,系统帮我们封装了起来(角度参数为angle),我们只需要设定一个角度就可以了。
所以系统通过的构造旋转操作的参数是:
CGAffineTransformMakeRotation(CGFloat angle)
CGAffineTransformRotate(CGAffineTransform t, CGFloat angle)
同样,前者是在初始化的基础上操作旋转(每次旋转先回到初始状态),而后者是在上一个参数(通常情况下是上一次的操作结果)的基础上旋转。
需要补充的动画基础
1.在每一个CALayer中,都有三个重要的层次树,它们负责相互协调完成图层的渲染展示效果。这三个层次树分别是:
模型树。通过layer.modelLayer获取,当我们修改CALayer的可动画属性时,模型树对应的属性就会立刻被修改成对应的数值
呈现树。通过layer. presentationLayer获取,呈现树保存着当前图层状态的显示数据,即会随着动画的过程不断更新图层的状态数据
渲染树,iOS并没有提供任何API来获取这一个层次树。顾名思义,它通过结合 modelLayer跟presentationLayer中设置的效果来将内容渲染到屏幕上
2.CAAnimation通过presentationLayer呈现的动画, 并不会实质改变modelLayer(即我们所说的layer)的值,所以动画完成后会自动回到初始状态; 而通过UIView动画, 改变的是实质数据(block里面修改View值),所以动画完成后, 会停留在最后状态.