给iOS图层添加动画

核心动画可以在layer上创造复杂的动画,比如修改大小、位置、旋转变换等等,也可以同时修改一个或多个属性。

简单修改layer属性做动画

首先理解下隐式动画和显示动画。当修改图层任意属性时都会出发隐式动画,隐式动画有默认时间步调和其他属性。如果不使用系统的默认动画可以通过创建CABasicAnimation对象指定图层的显示动画。调用addAnimation:forKey:方法把动画添加到图层上

在之前的矢量图上添加一个缩放的动画

CAShapeLayer *layer1 = [CAShapeLayer layer];
layer1.bounds = CGRectMake(0, 0, 200, 200);
layer1.position = self.view.center;
layer1.backgroundColor = [UIColor colorWithRed:0.9 green:0.3 blue:0.3 alpha:0.3].CGColor;
    
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:CGPointMake(50, 0)];
[path addCurveToPoint:CGPointMake(0, 50)
       controlPoint1:CGPointMake(50, 25)
       controlPoint2:CGPointMake(25, 50)];
    
[path addCurveToPoint:CGPointMake(-50, 0)
       controlPoint1:CGPointMake(-25, 50)
       controlPoint2:CGPointMake(-50, 25)];
    
[path addCurveToPoint:CGPointMake(0, -50)
       controlPoint1:CGPointMake(-50, -25)
       controlPoint2:CGPointMake(-25, -50)];
    
[path addCurveToPoint:CGPointMake(50, 0)
       controlPoint1:CGPointMake(25, -50)
       controlPoint2:CGPointMake(50, -25)];
CGAffineTransform transform = CGAffineTransformMakeTranslation(100, 100);
[path applyTransform:transform];
    
layer1.path = path.CGPath;
layer1.fillColor = [UIColor whiteColor].CGColor;
layer1.strokeColor = [UIColor blueColor].CGColor;
    
[self.view.layer addSublayer:layer1];
    
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];
animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.5, 1)];
animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.2, 0.2, 1)];
animation.duration = 4.0;
[layer1 addAnimation:animation forKey:@"animation1"];

<img src="http://upload-images.jianshu.io/upload_images/1840221-e8152fe11bd3915a.gif?imageMogr2/auto-orient/strip" width=250>

要注意,显式动画只是提供一个动画,它并不会修改图层对象的数据。所以在动画结束时,需要更新图层对象的数据。

动画会在runloop结束时开始执行,因此当前线程必须要有一个runloop才可以让动画执行。即便改变图层的多个属性或是添加多个动画,他们都会在同一时刻执行。比如你可以在移动的时候同时修改图层的不透明度。虽然他们是同时执行的,但是你可以单独配置每个属性的动画对象,控制他们属性变化的时间节奏。

用关键帧动画修改layer属性

关键帧动画可以在一个动画周期内给属性设置多个值。关键帧动画由一系列的值和每两个值之间变化时的时间节奏组成,他们都用数组表示。

CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
keyframeAnimation.keyTimes = @[@(0),@(0.3),@(0.5),@(1)];
keyframeAnimation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.5, 1.5, 1)],
                            [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.2, 1.2, 1)],
                            [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 0.2, 1)],
                            [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.3, 1.2, 1)]];
keyframeAnimation.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],
                                     [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                     [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                     [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]];
keyframeAnimation.duration = 8.f;
keyframeAnimation.fillMode = kCAFillModeForwards;
keyframeAnimation.removedOnCompletion = NO;
[layer1 addAnimation:keyframeAnimation forKey:@"transform2"];

<img src="http://upload-images.jianshu.io/upload_images/1840221-e58e4631a46e29fd.gif?imageMogr2/auto-orient/strip" width=250>

动画属性keyPath

在第一行创建关键帧动画时调用方法animationWithKeyPath,并传入动画属性keypath。CAPropertyAnimation定义了动画的属性值,它支持很多属性,具体可以查阅官方文档。

关键帧的值

通过动画的path或values来设置关键帧的值。属性是CGPoint类型的(锚点或位置)通常用动画的path属性来设置,path是CGPathRef类型。也可以用values属性来设置,它是数组类型。这时需要把CGPoint类型用NSValue来进行封装再添加到数组中,同样的CATransform3D和CGRect类型用NSValue封装、 CGFloat类型用NSNumber封装。

关键帧之间的节奏

关键帧动画的时间节奏和插值是通过一系列属性共同控制的:

  • calculationMode:动画中的计算算法,这个属性同时影响其他属性的使用
    • kCAAnimationLinear 或 kCAAnimationCubic,关键帧之间使用直线或圆滑曲线的插值算法实现。 当设置为kCAAnimationCubic时,可通过参数调整差值曲线函数来完全控制中间帧变化方法。
    • kCAAnimationPaced or kCAAnimationCubicPaced,使keyTimes和timingFunctions属性失效。动画平滑过渡,也就是匀速进行。
    • kCAAnimationDiscrete,使timingFunctions属性失效。动画在关键帧之间跳跃进行,也就是中间帧不进行差值计算,直接从两个关键帧变化。
  • keyTimes 指定每一个关键帧的属性值
  • timingFunctions 指定每两个关键帧之间过度的时间曲线变化

动画协议

你会发现第一个demo动画结束时,layer回到了初始状态,而第二个demo在开始和结束时layer保持动画开始和结束的状态。因为我设置了fillMode和removedOnCompletion这两个属性。layer的transform值始终都是CATransform3DIdentity,但是设置了这两个属性后可以让图层动画开始时就渲染到CATransform3DMakeScale(1.5, 1.5, 1),结束时渲染到CATransform3DMakeScale(0.3, 1.2, 1)。

CAMediaTiming协议是一套抽象接口,描述了动画的一些信息,CALayer和CAAnimation都实现了该协议

  • beginTime 相对于父图层或动画的开始时间
  • duration 动画的单次时长
  • speed 动画的播放速率,默认是1
  • timeOffset 动画的时间偏移,就是从哪里开始播放,默认是0
  • repeatCount 动画的重复播放次数,默认是0
  • repeatDuration 动画的有效时长,默认是0。结合重复次数使用
  • autoreverses 如果是true,动画正播后再进行反播。默认是false
  • fillMode 动画的填充模式,这就是上面用到的。可以四种情况:渲染开始和结束维持layer的属性值、在动画结束时layer渲染到动画结束时的属性、在动画开始时layer渲染到动画开始时的属性、开始结束都渲染。

removedOnCompletion是CAAnimation的属性,它表示动画一旦结束渲染就停止,所以第一个demo看到动画结束时layer又变回了初始的样子。

运行时停止动画

动画通常会一直运行到结束,如果想提前中止有两种方法:

  • 移除一个动画调用图层的removeAnimationForKey:方法,参数和添加动画时addAnimation:forKey:的第二个参数相同,都不能为nil
  • 移除全部动画调用图层的removeAllAnimations方法,它会马上中止所有正在进行的动画,并对layer进行重绘。但这个方法最好不要用!

当从图层移除一个动画的时候,会出发图层的重新绘制。图层会跳跃到动画之前状态,如果想保持最后一帧的状态可以通过修改图层属性实现。

动画组合

如果想图层一直执行多个动画,可以创建CAAnimationGroup对象通过配置animations属性来实现。动画组的的事件节奏和时长属性会覆盖掉所包含的动画属性。

检测动画结束

当动画开始和结束时,可以通过回调得知:

  • 对动画事物CATransaction添加setCompletionBlock:方法,在动画结束时调用
  • 动画对象实现animationDidStart:和animationDidStop:finished:方法

如果你想连接两个动画尽量不要用这种方式,通过设置动画的beginTime来实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容

  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥ios动画全貌。在这里你可以看...
    每天刷两次牙阅读 8,485评论 6 30
  • 在iOS中随处都可以看到绚丽的动画效果,实现这些动画的过程并不复杂,今天将带大家一窥iOS动画全貌。在这里你可以看...
    F麦子阅读 5,110评论 5 13
  • 书写的很好,翻译的也棒!感谢译者,感谢感谢! iOS-Core-Animation-Advanced-Techni...
    钱嘘嘘阅读 2,296评论 0 6
  • Core Animation Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,...
    45b645c5912e阅读 3,027评论 0 21
  • 在iOS实际开发中常用的动画无非是以下四种:UIView动画,核心动画,帧动画,自定义转场动画。 1.UIView...
    请叫我周小帅阅读 3,092评论 1 23