来来来,今天我们经过实现一个相似Twitter的启动动画来看看CAKeyFrame Animation和CAAnimation Group怎么玩。git
因此今天我们的重点到了第七章,CAKeyFrame Animation和CAAnimation Group。最后的那个启动动画彻底是为了实践一下看看CAKeyFrame Animation和CAAnimation Group怎么使用。swift
有读者私下说更新速度太慢了。在码云上看了一下下载的统计,发现其实下载的童鞋并非特别多。若是只是看看思路,或者复习一下这些基础知识,确实是很快。可是若是对于这些内容不是特别熟悉,建议仍是敲一边代码,看看本身能碰到什么坑。bash
俺写一篇分享文章大约要4~6个小时,大致是三部分:想到合适的例子,敲代码写注释,写文章。一般都会看本身当前的状况,决定是先写swift版仍是OC版,而后不动脑子的翻译成另一版调整一下BUG。这样也是为了训练本身,前段时间发现本身有时候会不自觉的把两种语言混在一块儿,这个习惯特别很差,因此想用这种方式本身纠正一下。到最后更新写文章的时候反而更轻松了,由于不用动脑。哈哈~并发
Come on~下面这张图纯粹是为了简书看成封面使用的。也不知道为何,之前简书还能自动把GIF的第一桢看成封面,如今很差使了。app
下面展现一下写完以后的成果:布局
源代码能够在这里下载,里面有OC和Swift两版。git.oschina.net/atypical/CA…学习
iOS动画系列之CAKeyFrame Animation和CAAnimation Group(OC和Swift两版)动画
CAKeyframeAnimation是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另外一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值。ui
建立步骤:spa
咱们用一个简单的demo来感觉一下CAKeyframeAnimation,来作一个会抖动的小方块。
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
//设置一些列的关键帧动画
animation.values = @[@(-M_PI_4 / 5),@(M_PI_4 / 5),@(-M_PI_4 / 5)];
animation.repeatCount = CGFLOAT_MAX;
[self.view.layer addAnimation:animation forKey:@"rotation"];复制代码
咱们建立一个UIBezierPath,让小飞机沿着这个路径运动。
//建立动画对象
CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
//设置属性:建立beziper路径,并把路径做为运动轨迹
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(100, 100, 200, 500)];
keyFrameAnimation.path = bezierPath.CGPath;
//设置动画时间
keyFrameAnimation.duration = 2;
//设置动画循环播放的次数
keyFrameAnimation.repeatCount = CGFLOAT_MAX;
//设置动画的计算模式
keyFrameAnimation.calculationMode = kCAAnimationPaced;
//将动画添加到layer上
[self.planeView.layer addAnimation:keyFrameAnimation forKey:nil];复制代码
刚才添加了一个沿路径运动的飞机,咱们同时还能够给飞机再把抖动的那个动画也添加上去。前几篇提到后面那个forKey
,可能还有童鞋不知道干啥用。如今看到了木有?一个layer里面好几个动画,如何找到对应的动画吶?如今经过这个key就能找到了。
// 为小飞机同时添加抖动的动画和椭圆路径旋转的动画
[self.planeImageView.layer addAnimation:[self shakeAni] forKey:nil];
[self.planeImageView.layer addAnimation:[self ovalAni] forKey:nil];复制代码
单一的动画在实际中每每是不能知足需求的,这时就须要用到动画组。
咱们试着作一个包行旋转、缩放、按必定弧度路径组合在一块儿的动画。效果以下:
- (CAAnimationGroup *)groupAni{
// 实例化一个组动画对象
CAAnimationGroup *groupAni = [[CAAnimationGroup alloc] init];
// 建立旋转的动画
CABasicAnimation *basicRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
basicRotation.toValue = @(M_PI * 2);
// 建立缩放的动画
CABasicAnimation *basicScale = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
basicScale.toValue = @(0.2);
// 建立按照路径移动的动画
CAKeyframeAnimation *keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@"position"];
UIBezierPath *arcPath = [UIBezierPath bezierPathWithArcCenter:self.view.center radius:150 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
keyFrameAni.path = arcPath.CGPath;
keyFrameAni.calculationMode = kCAAnimationPaced;
keyFrameAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
// 将旋转、缩放、移动的动画添加到组动画中
groupAni.animations = @[basicRotation,basicScale,keyFrameAni];
// 组动画重复次数
groupAni.repeatCount = CGFLOAT_MAX;
// 组动画时长
groupAni.duration = 2;
return groupAni;
}复制代码
1,在View上设置一个东西可以遮挡住背景图;
2,把遮罩变成五角星;
3,让遮罩慢慢变大,中间可见区域愈来愈大。
yes!思路就是这样的。那怎么遮住背景图片呢?
CALayer自己有一个属性,叫mask。咱们来看一下官方解释:
@property(nullable, strong) CALayer *mask;
When true an implicit mask matching the layer bounds is applied to
the layer (including the effects of the `cornerRadius' property). If both `mask' and `masksToBounds' are non-nil the two masks are multiplied to get the actual mask values. Defaults to NO. Animatable.复制代码
它相似于一个子图层,相对于父图层(即拥有该属性的图层)布局,可是它却不是一个普通的子图层。不一样于其余可以在父图层中绘制出图像的子图层,mask图层定义了父图层的部分可见区域。
mask图层的Color属性是可有可无的,真正重要的是图层的轮廓。也就是说mask图层实心的部分会被保留下来,其余的则会被抛弃。若是mask图层比父图层要小,只有在mask图层里面的内容才是它关心的,除此之外的一切都会被隐藏起来。
好了准备工做都作完了,咱们就开始写这个动画了。这个动画其实就是一个简单的CAKeyframeAnimation。设置了三个关键帧动画的大小,以及这三个关键帧的运动节奏。
而后,就好啦~而后,就好啦~而后,就好啦~而后,就好啦~
哪尼?!!!就这样?!!对啊,就这样。
- (CAKeyframeAnimation *)maskAni{
// 放大缩小视图,keypath使用bounds
CAKeyframeAnimation *maskAni = [CAKeyframeAnimation animationWithKeyPath:@"bounds"];
// 动画时间
maskAni.duration = 30.75;
// 动画延迟0.5秒播放
maskAni.beginTime = CACurrentMediaTime() + 0.5;
// 设置关键帧动画的数值
CGRect startRect = self.maskLayer.frame;
CGRect tempRect = CGRectMake(0, 0, 100, 100);
CGRect finalRect = CGRectMake(0, 0, 2000, 2000);
maskAni.values = @[[NSValue valueWithCGRect:startRect],[NSValue valueWithCGRect:tempRect],[NSValue valueWithCGRect:finalRect]];
// 设置关键帧动画的运动节奏
maskAni.timingFunctions = @[[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut],[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
// 动画播放结束后是否移除动画
maskAni.removedOnCompletion = NO;
// 动画填充模式:kCAFillModeForwards:当动画结束后,layer会一直保持着动画最后的状态
maskAni.fillMode = kCAFillModeForwards;
return maskAni;
}复制代码
留一个小问题:
我在OC和Swift里面对不一样的View使用了mask。一个是给背景图片的UIImageView设置了mask,另外一个是直接给Controller的View设置了mask。设置这两个有神马区别咩?
好,下篇其实有一个重头,就是CAShapeLayer。由于在工做中碰到的大部分动画都是经过UIView的动画block实现,其余都基本上都是须要用到CAShapeLayer。咱们下次玩点好玩的吧~
若是还有兴趣,能够看看本系列的其余文章哈。
-----------------------华丽分割线,iOS动画系列全集连接-------------------------------------------------
第一篇:iOS动画系列之一:经过实战学习CALayer和透视的原理。作一个带时分秒指针的时钟动画(上)
第二篇:iOS动画系列之二:经过实战学习CALayer和透视的原理。作一个带时分秒指针的时钟动画。包含了OC和Swift两种源代码(下)
第三篇:iOS动画系列之三:Core Animation。介绍了Core Animation的经常使用属性和方法。
第四篇:CABasic Animation。iOS动画系列之四:基础动画之平移篇
第五篇:CABasic Animation。iOS动画系列之五:基础动画之缩放篇&旋转篇
第六篇:iOS动画系列之六:利用CABasic Animation完成带动画特效的登陆界面
第七篇:iOS动画系列之七:实现相似Twitter的启动动画
第八篇:iOS动画系列之八:使用CAShapeLayer绘画动态流量图
第九篇:iOS动画系列之九:实现点赞的动画及播放起伏指示器
第十篇:实战系列:绘制过山车场景