当你给一个 CALayer 添加动画的时候,动画其实并没有改变这个 layer 的实际属性。取而代之的,系统会创建一个原始 layer 的拷贝。在文档中,苹果称这个原始 layer 为 Model Layer ,而这个复制的 layer 则被称为 Presentation Layer 。 Presentation Layer 的属性会随着动画的进度实时改变,而 Model Layer 中对应的属性则并不会改变。这里就可以引出 removedOnCompletion 和fillMode 了。
removedOnCompletion 的官方解释是:
/* When true, the animation is removed from the render tree once its
* active duration has passed. Defaults to YES. */
/ *当为真时,动画从渲染树中删除一次
*活动时间已经过去。默认值为YES。* /
也就是默认情况下系统会在 duration 时间后自动移除这个 CAKeyframeAnimation。当 remove 了某个动画,那么系统就会自动销毁这个 layer 的 Presentation Layer ,只留下 Model Layer 。 而前面提到 Model Layer 的属性其实并没有变化,所以也就有了你前面看到的结果,视图在一瞬间回到了动画的初始状态。要解决这种情况,你需要先把removedOnCompletion 设置为 no ,然后设置fillMode 为kCAFillModeForwards 。关于 fillMode ,它有四个值:
kCAFillModeRemoved 这个是默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态。
kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态。
kCAFillModeBackwards 这个和 kCAFillModeForwards 是相对的,就是在动画开始前,你只要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。你可以这样设定测试代码,将一个动画加入一个layer的时候延迟5秒执行。然后就会发现在动画没有开始的时候,只要动画被加入了 layer , layer 便处于动画初始状态, 动画结束后,layer 也会恢复到之前的状态。
kCAFillModeBoth 理解了上面两个,这个就很好理解了,这个其实就是上面两个的合成。动画加入后立即开始,layer便处于动画初始状态,动画结束后layer保持动画最后的状态。
calculationMode 设置是否匀速线性运动
默认是kCAAnimationLinear线性运动走直角
const kCAAnimationLinear//线性,默认
2 const kCAAnimationDiscrete//离散,无中间过程,但keyTimes设置的时间依旧生效,物体跳跃地出现在各个关键帧上
3 const kCAAnimationPaced//平均,keyTimes跟timeFunctions失效
4 const kCAAnimationCubic//平均,同上
5 const kCAAnimationCubicPaced//平均,同上
属性理解
duration 动画的时长
repeatCount 重复的次数。不停重复设置为 HUGE_VALF
repeatDuration 设置动画的时间。在该时间内动画一直执行,不计次数。
beginTime 指定动画开始的时间。从开始延迟几秒的话,设置为【CACurrentMediaTime() + 秒数】 的方式
timingFunction 设置动画的速度变化
autoreverses 动画结束时是否执行逆动画
fromValue 所改变属性的起始值
toValue 所改变属性的结束时的值
byValue 所改变属性相同起始值的改变量
UIView *aView0 = [[UIView alloc] initWithFrame:CGRectMake(150, 100, 50, 50)];
[self.view addSubview:aView0];
aView0.backgroundColor = [UIColor purpleColor];
//旋转动画
//transform.rotation 默认围绕z轴
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"transform.rotation.z";
animation11.values = @[@0, @(M_PI*2)];
animation11.duration = 5;
animation11.repeatCount = MAXFLOAT;
animation11.calculationMode = kCAAnimationCubic;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
[aView0.layer addAnimation:animation11 forKey:nil];
//缩放动画
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"transform.scale";
animation11.values = @[@1.0,@1.2,@0.9,@1.15,@0.95,@1.05,@1.0];
animation11.duration = 5;
animation11.repeatCount = MAXFLOAT;
animation11.calculationMode = kCAAnimationCubic;
[aView0.layer addAnimation:animation11 forKey:nil];
//位移动画 设置偏移距离
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"transform.translation.x";
animation11.values = @[@1, @-100.0,@110];
animation11.duration = 5;
animation11.repeatCount = 1;
animation11.calculationMode = kCAAnimationCubic;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
[aView0.layer addAnimation:animation11 forKey:nil];
// 位移动画 设置 运动坐标点
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"transform.translation";
animation11.values = @[@(CGPointMake(0, 0)),@(CGPointMake(100, 200)), @(CGPointMake(50, 200))];
animation11.duration = 1;
animation11.repeatCount = 1;
animation11.calculationMode = kCAAnimationLinear;//这里是线性 如果转弯的话不会飘;
/*
const kCAAnimationLinear//线性,默认
2 const kCAAnimationDiscrete//离散,无中间过程,但keyTimes设置的时间依旧生效,物体跳跃地出现在各个关键帧上
3 const kCAAnimationPaced//平均,keyTimes跟timeFunctions失效
4 const kCAAnimationCubic//平均,同上
5 const kCAAnimationCubicPaced//平均,同上
*/
animation11.autoreverses = NO;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
[aView0.layer addAnimation:animation11 forKey:nil];
//设置 透明度
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"opacity";
animation11.values = @[@1.0, @0.7, @0.4, @0.8, @0.1, @0.5, @0.2];
animation11.duration = 2;
animation11.repeatCount = 1;
animation11.calculationMode = kCAAnimationCubic;
animation11.autoreverses = NO;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
[aView0.layer addAnimation:animation11 forKey:nil];
//圆角
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"cornerRadius";
animation11.values = @[@0, @20, @25, @25, @0, @25];
animation11.duration = 2;
animation11.repeatCount = 1;
animation11.calculationMode = kCAAnimationCubic;
animation11.autoreverses = NO;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
[aView0.layer addAnimation:animation11 forKey:nil];
//边框宽度
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"borderWidth";
animation11.values = @[@0, @20, @10, @0, @10];
animation11.duration = 2;
animation11.repeatCount = 1;
animation11.calculationMode = kCAAnimationCubic;
animation11.autoreverses = NO;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
aView0.layer.borderColor = [UIColor redColor].CGColor;
[aView0.layer addAnimation:animation11 forKey:nil];
//bounds大小
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"bounds";
animation11.values = @[@(CGRectMake(0, 0, 50, 50)), @(CGRectMake(0, 0, 100, 120)), @(CGRectMake(0, 0, 70, 50))];
animation11.duration = 2;
animation11.repeatCount = 1;
animation11.calculationMode = kCAAnimationCubic;
animation11.autoreverses = NO;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
[aView0.layer addAnimation:animation11 forKey:nil];
//位移动画 设置点
CAKeyframeAnimation *animation11 = [CAKeyframeAnimation animation];
animation11.keyPath = @"position";
animation11.values = @[[NSValue valueWithCGPoint:CGPointMake(150, 100)],[NSValue valueWithCGPoint:CGPointMake(300, 300)],[NSValue valueWithCGPoint:CGPointMake(300, 200)]];
animation11.duration = 2;
animation11.repeatCount = 1;
animation11.calculationMode = kCAAnimationLinear;//这里是线性 如果转弯的话不会飘
animation11.autoreverses = NO;
animation11.removedOnCompletion = NO;
animation11.fillMode = kCAFillModeForwards;
[aView0.layer addAnimation:animation11 forKey:nil];
//组合动画
//位置在y周平移
CABasicAnimation *positionAnima = [CABasicAnimation animationWithKeyPath:@"position.y"];
positionAnima.fromValue = @(bgImageView.center.y);
positionAnima.toValue = @(bgImageView.center.y-30);
positionAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
//相对y周旋转
CABasicAnimation *transformAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.y"];
transformAnima.fromValue = @(0);
transformAnima.toValue = @(M_PI);
transformAnima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
//组合动画类
CAAnimationGroup *animaGroup = [CAAnimationGroup animation];
animaGroup.duration = 2.0f;
animaGroup.fillMode = kCAFillModeForwards;
animaGroup.removedOnCompletion = NO;
animaGroup.autoreverses = YES;
animaGroup.repeatCount = CGFLOAT_MAX;
//添加组合动画
animaGroup.animations = @[positionAnima,transformAnima];
//添加到实现动画对象的layer
[bgImageView.layer addAnimation:animaGroup forKey:@"Animation"];