iOS动画系列之七:实现类似Twitter的启动动画1. CAKeyframeAnimation2. CAAnimationGroup3. 实现类似Twitter的启动动画

来来来,今天咱们通过实现一个类似Twitter的启动动画来看看CAKeyFrame Animation和CAAnimation Group怎么玩。

所以今天咱们的重点到了第七章,CAKeyFrame Animation和CAAnimation Group。最后的那个启动动画完全是为了实践一下看看CAKeyFrame Animation和CAAnimation Group怎么使用。

有读者私下说更新速度太慢了。在码云上看了一下下载的统计,发现其实下载的童鞋并不是特别多。如果只是看看思路,或者复习一下这些基础知识,确实是很快。但是如果对于这些内容不是特别熟悉,建议还是敲一边代码,看看自己能碰到什么坑。

俺写一篇分享文章大约要4~6个小时,大体是三部分:想到合适的例子,敲代码写注释,写文章。通常都会看自己当前的情况,决定是先写swift版还是OC版,然后不动脑子的翻译成另外一版调整一下BUG。这样也是为了训练自己,前段时间发现自己有时候会不自觉的把两种语言混在一起,这个习惯特别不好,所以想用这种方式自己纠正一下。到最后更新写文章的时候反而更轻松了,因为不用动脑。哈哈~

Come on~下面这张图纯粹是为了简书当作封面使用的。也不知道为什么,以前简书还能自动把GIF的第一桢当作封面,现在不好使了。

CAKeyFrame Animation和CAAnimation Group.png

下面展示一下写完之后的成果:

ani.gif

源代码可以在这里下载,里面有OC和Swift两版。https://git.oschina.net/atypical/CAKeyFrame-_Group_Animation.git

iOS动画系列之CAKeyFrame Animation和CAAnimation Group(OC和Swift两版)

1. CAKeyframeAnimation

CAKeyframeAnimation是CApropertyAnimation的子类,跟CABasicAnimation的区别是:CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue),而CAKeyframeAnimation会使用一个NSArray保存这些数值。

创建步骤:

  1. 创建关键帧动画对象
  2. 设置属性
  3. 添加到要作用的layer上
  • 如果使用rect椭圆的方式,动画会不连贯,停顿一下。原因是因为矩形的周长比椭圆的长,动画路径按照椭圆执行完之后,需要等待一下最大周长走完。 这些都是因为计算模式导致的。

1.1 创建一个抖动的小方块

我们用一个简单的demo来感受一下CAKeyframeAnimation,来做一个会抖动的小方块。

抖动的小方块.gif

    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"];

1.2 创建一个沿椭圆路径运动的小飞机

我们创建一个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];

1.3 动画叠加

刚才添加了一个沿路径运动的飞机,我们同时还可以给飞机再把抖动的那个动画也添加上去。前几篇提到后面那个forKey,可能还有童鞋不知道干啥用。现在看到了木有?一个layer里面好几个动画,如何找到对应的动画吶?现在通过这个key就能找到了。

    //        为小飞机同时添加抖动的动画和椭圆路径旋转的动画
    [self.planeImageView.layer addAnimation:[self shakeAni] forKey:nil];
    [self.planeImageView.layer addAnimation:[self ovalAni] forKey:nil];

2. CAAnimationGroup

单一的动画在实际中往往是不能满足需求的,这时就需要用到动画组。

  • 是CAAnimation的子类
  • 可以保存一组动画对象,将CAAnimationGroup对象加入图层后,组中所有动画对象可以同时并发运行.

我们试着做一个包行旋转、缩放、按一定弧度路径组合在一起的动画。效果如下:

arcAni.gif

- (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;
}

3. 实现类似Twitter的启动动画

3.1实现思路

1,在View上设置一个东西能够遮挡住背景图; 2,把遮罩变成五角星; 3,让遮罩慢慢变大,中间可见区域越来越大。

yes!思路就是这样的。那怎么遮住背景图片呢?

3.2 CALayer的遮罩属性

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图层里面的内容才是它关心的,除此以外的一切都会被隐藏起来。

Paste_Image.png

3.3 实现类似Twitter的启动动画

好了准备工作都做完了,我们就开始写这个动画了。这个动画其实就是一个简单的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。我们下次玩点好玩的吧~ 如果还有兴趣,可以看看本系列的其他文章哈。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

iOS动画总结

在iOS开发中,动画是提高用户体验重要的环节之一。一个设计严谨、精细的动画效果能给用户耳目一新的效果,这对于app而言是非常重要的。 简介 iOS动画主要是指C...

2258
来自专栏Android群英传

onTouchEvent(二) 使用Scroller实现黏性滑动的ScrollView

673
来自专栏微信终端开发团队的专栏

iOS 事件处理机制与图像渲染过程

致歉声明: Peter在开发公众号功能时触发了一个bug,导致群发错误。对此我们深表歉意,并果断开除了Peter。以下交回给正文时间: iOS 事件处理机制与...

7838
来自专栏老司机的简书

老司机带你走进Core Animation 之CAAnimation

开玩笑的,前段时间ipv6被拒啊,超级悲剧的,前后弄了好久,然后需求啊什么的又超多,所以写好的东西也没有时间整理。不过既然我现在回来了,那么这将是一个井喷的时节...

872
来自专栏前端新视界

关于 CSS 反射倒影的研究思考

原文:The State of CSS Reflections 译者:nzbin 友情提示:由于演示 demo 的兼容性,推荐火狐浏览。该文章篇幅较长,内容庞杂...

2739
来自专栏IT 指南者专栏

Python 从入门到入门基础练习十五题

微信公众号:compassblog 欢迎关注、转发,互相学习,共同进步! 有任何问题,请后台留言联系! ? 1、永远的 HelloWorld print("He...

5047
来自专栏向治洪

ios动画

在iOS开发中,动画是提高用户体验重要的环节之一。一个设计严谨、精细的动画效果能给用户耳目一新的效果,这对于app而言是非常重要的。 简介 iOS动画主要是指C...

1915
来自专栏有趣的django

python开发面试问题

python语法以及其他基础部分 可变与不可变类型;  浅拷贝与深拷贝的实现方式、区别;deepcopy如果你来设计,如何实现;  __new__() 与 __...

4158
来自专栏听雨堂

快速制作边框的心得

常常需要制作一个边框,中间放个半透明的板子,用来放置文字,最快的方法是: 1、画一个圆边矩形 2、保存选区,再画收缩之或者自由变换选区,两者运算,求出边框 3、...

1749
来自专栏葡萄城控件技术团队

CoffeeScript和Sass提高Web开发效率

如果您是一位每天都要编写JavaScript和Css的Web前端开发人员,可能您已经开始感觉到JavaScript的关键字 var, function, {} ...

1907

扫码关注云+社区