CALayer动画实践(二):CAReplicatorLayer的用法

http://www.csdn.net/article/2015-09-09/2825659?utm_source=tuicool


CALayer动画实践(二):CAReplicatorLayer的用法

CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用、开发工具、移动游戏及引擎、智能硬件、物联网等方方面面。如果您想投稿、参与内容翻译工作,或寻求近匠报道,请发送邮件至tangxy#csdn.net(请把#改成@)。 


上一篇文章通过两个动画示例带大家了解和认识了CALayer动画,包括如何使用CAShapeLayer、CABasicAnimation、CAAnimationGroup等。在这篇文章中,依然会通过两个示例向大家讲解更多CALayer动画的知识。

老规矩,先让我们看看最终要实现的动画效果:

ReplicatorAnimation-17

经常听音乐的人对第一个动画效果肯定有会觉得很眼熟,类似播放音乐时音频高低起伏的动画,这种动画在应用中常被用作标识正在播放音乐或广播。第二个动画依然是一个等待加载的动画,在我的印象中肯定是有应用使用过,具体的已经记不清了。下面就让我们来实现这两个动画吧。

Replicator Animation

新建一个项目,名为ReplicatorAnimation,打开Main.storyboard,添加一个UIView,颜色位置按大家喜好设定:

ReplicatorAnimation-1

添加该UIView在ViewController.swift中的Outlet:

ReplicatorAnimation-2

接下来我们在ViewController.swift中添加一个方法firstReplicatorAnimation(),在该方法中编写如下代码:

[cpp]  view plain copy
  1. let replicatorLayer = CAReplicatorLayer()  
  2. replicatorLayer.bounds = CGRect(x: replicatorAnimationView.frame.origin.x, y: replicatorAnimationView.frame.origin.y, width: replicatorAnimationView.frame.size.width, height: replicatorAnimationView.frame.size.height)  
  3. replicatorLayer.anchorPoint = CGPoint(x: 0, y: 0)  
  4. replicatorLayer.backgroundColor = UIColor.lightGrayColor().CGColor  
  5. replicatorAnimationView.layer.addSublayer(replicatorLayer)  

这里出现的CAReplicatorLayer是一个新面孔,它也是CALayer的子类,正如它的名称一样,CAReplicatorLayer可以对它自己的子Layer进行复制操作。创建了CAReplicatorLayer实例后,设置了它的尺寸大小、位置、锚点位置、背景色,并且将它添加到了replicatorAnimationView的Layer中:

ReplicatorAnimation-4

这里要啰嗦几句,Layer的默认锚点坐标是(0.5, 0.5),也就是Layer的中心点位置,而Layer的position又是根据锚点计算的,所以如果你设置Layer的position属性为(10, 10),就相当于设置了Layer的中心位置为(10, 10),并不是你期望的左上角位置。所以如果Layer想使用它父视图的坐标位置,就需要将锚点位置设置为(0, 0),这样一来Layer的position属性标识的就是Layer左上角的位置:

ReplicatorAnimation-3

然后我们继续在firstReplicatorAnimation()方法中添加代码:

[cpp]  view plain copy
  1. let rectangle = CALayer()  
  2. rectangle.bounds = CGRect(x: 0, y: 0, width: 30, height: 90)  
  3. rectangle.anchorPoint = CGPoint(x: 0, y: 0)  
  4. rectangle.position = CGPoint(x: replicatorAnimationView.frame.origin.x + 10, y: replicatorAnimationView.frame.origin.y + 110)  
  5. rectangle.cornerRadius = 2  
  6. rectangle.backgroundColor = UIColor.whiteColor().CGColor  
  7. replicatorLayer.addSublayer(rectangle)  

通过上面的代码,再次创建了一个Layer,这次使用的是CALayer,因为我们只需要一个很普通的Layer,为其设置位置、尺寸、背景色、圆角属性,然后添加在replicatorLayer中:

ReplicatorAnimation-5

动画的主体之一已经绘制好了,下面我们让它动起来。在上述代码后面,接着添加如下代码:

[cpp]  view plain copy
  1. let moveRectangle = CABasicAnimation(keyPath: "position.y")  
  2. moveRectangle.toValue = rectangle.position.y - 70  
  3. moveRectangle.duration = 0.7  
  4. moveRectangle.autoreverses = true  
  5. moveRectangle.repeatCount = HUGE  
  6. rectangle.addAnimation(moveRectangle, forKey: nil)  

首先我们创建了按Y轴移动的动画实例,然后设置了移动的目标位置,动画持续时间,重复次数设置为无限大。这里有一个属性大家可能比较陌生,那就是autoreverses,这个属性为Bool类型,设置为true时,开启自动反向执行动画,比如示例中的白色长方形的移动动画为向上移动50个像素,如过autoreverses设置为false,那么动画结束后,会根据重复次数,白色长方形重新回到初始位置,继续向上移动,如果autoreverses设置为true,则当动画结束后,白色长方形会继续向下移动至初始位置,然后再开始第二次的向上移动动画。

编译运行看看效果:

ReplicatorAnimation-6

至此,大家应该也已经看出来了,这个白色的长方形就是动画中第一个上下移动的白色长方形,那么后两个如何创建呢?还需要再写两遍上面的代码吗?请大家在下面的文章中寻找答案。

在上述代码下面再添加一行代码:

[cpp]  view plain copy
  1. replicatorLayer.instanceCount = 3  

显而易见,这是CAReplicatorLayer的能力了,这行代码的意思是将replicatorLayer的子Layer复制3份,复制Layer与原Layer的大小、位置、颜色、Layer上的动画等等所有属性都一模一样,所以这时编译运行代码我们看不到任何不同的效果,因为三个白色长方形是重合在一起的,所以我们需要设置每个白色长方形的间隔:

[cpp]  view plain copy
  1. replicatorLayer.instanceTransform = CATransform3DMakeTranslation(40, 0, 0)  

这行代码涉及到CAReplicatorLayer的另一个属性instanceTransform,它的作用是设置每个子Layer如何变化。CATransform3DMakeTranslation这个类的含义是使Layer根据X、Y、Z轴进行平移。现在再编译运行看看效果如何:

ReplicatorAnimation-7

现在三个白色长方形的运动轨迹和时刻都是一直的,这显然不是我们想要的结果,我们需要三个白色长方形有上下起伏的视觉效果,所以我们继续添加一行代码:

[cpp]  view plain copy
  1. replicatorLayer.instanceDelay = 0.3  

instanceDelay这个属性使CAReplicatorLayer中的每个子Layer的动画起始时间逐个递增。这里我们设置为0.3秒,也就是第一个长方形先执行动画,过0.3秒后第二个开始执行动画,再过0.3秒后第三个开始执行动画。我们编译运行看看效果:

ReplicatorAnimation-8

显然我们只想显示 replicatorLayer 区域里的内容,我们并不想看到超出它边界的内容,所以我们再添加一行代码:

[cpp]  view plain copy
  1. replicatorLayer.masksToBounds = true  

masksToBounds是CALayer的属性,作用是将Layer视为一个遮罩,只显示遮罩区域内的内容。最后我们回到初始化replicatorLayer的地方,找到这行代码replicatorLayer.backgroundColor = UIColor.lightGrayColor().CGColor,将replicatorLayer的背景色改为无色replicatorLayer.backgroundColor = UIColor.clearColor().CGColor。再次编译运行看看最终效果:

ReplicatorAnimation-9

Replicator Indicator Animation

CAReplicatorLayer的功能是很强大的,这一节将通过另一个加载动画的实例向大家介绍它的其他特性。

首先打开Main.storyboard,拖进一个新的UIView,位置颜色随大家喜好:

ReplicatorAnimation-10

随后添加该UIView在ViewController.swift中的Outlet activityIndicatorView

ReplicatorAnimation-11

然后在ViewController.swift中添加一个方法activityIndicatorAnimation,和上一个动画示例一样,我们先创建一个CAReplicatorLayer:

[cpp]  view plain copy
  1. let replicatorLayer = CAReplicatorLayer()  
  2. replicatorLayer.bounds = CGRect(x: 0, y: 0, width: activityIndicatorView.frame.size.width, height: activityIndicatorView.frame.size.height)  
  3. replicatorLayer.position = CGPoint(x: activityIndicatorView.frame.size.width/2, y: activityIndicatorView.frame.size.height/2)  
  4. replicatorLayer.backgroundColor = UIColor.lightGrayColor().CGColor  
  5. activityIndicatorView.layer.addSublayer(replicatorLayer)  

上述代码和上个示例中的差不多,唯一不同的就是replicatorLayer的锚点使用的是默认值,即锚点就是中点,position属性代表亦是中点,所以将position属性设置为父视图的中点即可。这里意在让大家多多理解CALayer中anchorPointposition属性。接下来添加如下代码:

[cpp]  view plain copy
  1. let circle = CALayer()  
  2. circle.bounds = CGRect(x: 0, y: 0, width: 15, height: 15)  
  3. circle.position = CGPoint(x: activityIndicatorView.frame.size.width/2, y: activityIndicatorView.frame.size.height/2 - 55)  
  4. circle.cornerRadius = 7.5  
  5. circle.backgroundColor = UIColor.whiteColor().CGColor  
  6. replicatorLayer.addSublayer(circle)  

上述代码的目的是用CALayer创建一个圆形,其实CALayer创建出的形状默认是矩形,但是把四个角的弧度设置为边宽的一半,矩形就变成了圆形。将这个圆形的位置设置在父Layer的中间靠上位置,背景色设置为白色。此时该圆形就是文章开头效果图中第二个动画里的主体了:

ReplicatorAnimation-12

不过在动画中我们看到有许多个小圆形组成一个大圆,如果重复上面的代码,一个一个设置位置,那绝对是令人发指的行为,好在我们有CAReplicatorLayer帮助我们实现,下面就来看看如何使用CAReplicatorLayer复制子Layer,并让子Layer形成一个圆形。让我们接着添加如下代码:

[cpp]  view plain copy
  1. replicatorLayer.instanceCount = 15  
  2. let angle = CGFloat(2 * M_PI) / CGFloat(15)  
  3. replicatorLayer.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1)  

上述的代码中,首先对子Layer,也就是白色圆形复制了15份。然后将360°除以15份,算出每一个圆形针对它前一个圆形应该偏移的角度。最后我们用到了CATransform3DMakeRotation,它同样是CATransform3D的一个结构,含义是使Layer在X、Y、Z轴根据给定的角度旋转。这样我们复制的15份圆形就会按照我们计算的角度排列,并形成一个大圆:

ReplicatorAnimation-13

接下来让我们分析一下这个动画,整体看上去感觉像一颗流星拖着尾巴在不停的转圈,但细看每一个小圆点,其实是在不停的进行放大缩小的动画,只不过每个小圆点的动画对于它前一个小圆点的动画有一定的延迟。所以首先我们需要实现小圆点放大缩小的动画,在上述代码后面接着添加如下代码:

[cpp]  view plain copy
  1. let scale = CABasicAnimation(keyPath: "transform.scale")  
  2. scale.fromValue = 1  
  3. scale.toValue = 0.1  
  4. scale.duration = 1  
  5. scale.repeatCount = HUGE  
  6. circle.addAnimation(scale, forKey: nil)  

首先创建一个按比例缩放类型的动画,设置起始比例为1,也就是当前大小。再设置希望缩放到的比例为0.1。动画持续时间为1秒,重复无限次。最后将该动画添加在小圆点中。编译运行看看效果:

ReplicatorAnimation-14

目前每个小圆点是同时执行动画,我们需要设置小圆点的动画延迟时间,接着添加如下代码:

[cpp]  view plain copy
  1. replicatorLayer.instanceDelay = 1/15  

这里为什么是1/15呢,因为整个动画的时间是由每个小圆点的动画时间决定的,这里也就是1秒,所有小圆点的延迟时间加起来要等于整个动画的持续时间,所以这里就是用1秒除以小圆点的数量15。编译运行看看效果:

ReplicatorAnimation-15

从效果图中可以看到,刚开始的动画不是很自然,那是因为小圆点的初始比例是1,所以一开始会先看到小圆点,然后才会慢慢开始正常的动画。这个问题很好解决,我们让小圆点的初始比例为0.1,也就是刚开始看不到小圆点,这样就可以避免这个情况了,我们接着加一行代码:

[cpp]  view plain copy
  1. circle.transform = CATransform3DMakeScale(0.01, 0.01, 0.01)  

同时将replicatorLayer的背景色改为无色,再次编译运行看看效果:

ReplicatorAnimation-16

展现在我们眼前的是一个完美的加载动画。

总结

今天主要给大家介绍了CAReplicatorLayer的用法,大家领悟其核心功能复制、延迟后也可以尝试实现其他有趣的动画效果。下篇文章我会向大家介绍CALayer另一个子类的用法,敬请期待吧。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值