原文:Creating animations with CAReplicatorLayer
作者:Marin Todorov
译者:kmyhy

本教程针对 Xcode 7/Swift 2 或更高版本。

CAReplicatorLayer 绝对是我最爱的 CALayer,因此我很愿意向你介绍如何用它来创建动画。

在本教程中,我将向你展示用 CAReplicatorLayer 创建 3 种不同的动画。

首先模拟一个类似 iOS 音乐 app 中的音量条动画(在“Pyramid Song”右边有一个会动的柱状图):

然后创建一个自定义的进度指示器。最后以一种非同一般的效果渲染出 ranywenderlich.com 的网站 logo。

1. 基本的 replicator 动画

CAReplicatorLayer 是一个容器图层——你向它上面添加内容,然后 CAReplicatorLayer 会重复这些内容。如果你放入的是单个形状——CAReplicatorLayer 会在屏幕上显示多个形状。

有意思的是,你可以提前告诉 replicator 在这个复制的内容之间要偏移多少,alpha 是多少以及一个拷贝和另一个拷贝之间颜色如何改变。这允许你创建出非常炫的效果和动画。

本教程的第一部分是模拟 iOS Music app 的动画:

这个动画会画一个红色的会上下动的柱子,复制两个这样的动画进,然后对形状和时间进行一点偏移。让我们开始吧!

新建 Single View Application 项目。打开 ViewController.swift。

在 viewDidLoad() 中添加:

animation1()

然后添加一个空方法:

func animation1() {}

在 animation1 方法中创建 CAReplicatorLayer:

let r = CAReplicatorLayer()
r.bounds = CGRect(x: 0.0, y: 0.0, width: 60.0, height: 60.0)
r.position = view.center
r.backgroundColor = UIColor.lightGrayColor().CGColor
view.layer.addSublayer(r)

你创建了一个 CAReplicatorLayer 对象,设置它的 bounds 和位置。为了能够看得清它的位置,可以为它指定一个浅灰色的背景色,然后将它添加到 view controller 的 view。

运行 app,你会看到一个灰色方块:

首先创建第一个 bar(也就是最初的 bar),在 animation1 中添加:

let bar = CALayer()
bar.bounds = CGRect(x: 0.0, y: 0.0, width: 8.0, height: 40.0)
bar.position = CGPoint(x: 10.0, y: 75.0)
bar.cornerRadius = 2.0
bar.backgroundColor = UIColor.redColor().CGColorr.addSublayer(bar)

这段代码创建了一个红色的圆角矩形,将它放到 replicator layer 的左边。运行 app 看看效果:

这个 bar 显示到了 replicator layer 的外边了,因为你将上下移动它。在动画一开始它将位于 replicator layer 的边界之下——因此它看起来是“关闭”的样子。

然后是 bar 动画,添加动画代码如下:

let move = CABasicAnimation(keyPath: "position.y")
move.toValue = bar.position.y - 35.0
move.duration = 0.5
move.autoreverses = true
move.repeatCount = Float.infinitybar.addAnimation(move, forKey: nil)

这将让 bar 反复地上移下移… 这是一个了不起的开始,哪怕目前它看起来是那么的不起眼,但实际上你已经为最终的动画做好了准备!

接下来看看 replicator 的威力!在你的代码中添加:

r.instanceCount = 3

这会告诉 replicator 你将在屏幕内容中创建 3 个拷贝——包括你最初的那个在内。如果你运行 app,你不会看到任何区别,因为 3 个拷贝是在同一个位置以同时同步的方式显示的。要将每个拷贝的位置向右添加一点偏移,只需要:

r.instanceTransform = CATransform3DMakeTranslation(20.0, 0.0, 0.0)

这里你告诉 replicator layer 每个拷贝要应用的矩形变换。你将 instanceTransform 设置为每个拷贝偏移 20 像素,这样当运行 app 时就会看到 3 个 bar 一个挨着一个排列了:

啊!你原始的 bar 和另外两个拷贝都会上下移动……很好!最后一个步骤是给每个 bar 一个延时,以便它们不会一起动。最后加一句代码:

r.instanceDelay = 0.33

instanceDelay 是 replicator 在渲染每个拷贝的时间差。应用到原始 bar 的动画和第二个拷贝的动画之间有 0.33 秒的延迟,而它和第 3 个 bar 的延迟为 0.66。

运行 app,测试一下结果——你会看到这些 bar 就像原本的动画一样跳动着。

最后还有两个地方:

  • 要想只显示 bar 和 replicator layer 相交的上部分,请用:.masksToBounds = true;
  • 找到设置 replicator layer 的背景色的一行,删掉它。你不再需要灰色背景了。

最终动画效果如下:

如果你想尝试做些改变,可以修改 instanceCount、instanceTransform 和 instanceDelay。很酷吧?

2. 进度指示器

让我们来看一下更复杂的 replicator 动画!将 viewDidLoad() 中的 animation1() 改为:

animation2()

你可能猜到了,下一步你将添加一个空方法:

func animation2() {}

在这部分你将创建一个进度指示器。为了好玩,你将创建一个比内置 iOS activity view 更复杂的动画。

首先在 animation2() 方法中,添加一个 replicator layer 到 view controller 的 view 中:

let r = CAReplicatorLayer()
r.bounds = CGRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0)
r.cornerRadius = 10.0
r.backgroundColor = UIColor(white: 0.0, alpha: 0.75).CGColor
r.position = view.centerview.layer.addSublayer(r)

和之前一样,创建一个灰色背景的空的 replicator layer。这次你将保留背景色已模仿 HUD activity。

然后绘制一个白色的矩形:

let dot = CALayer()
dot.bounds = CGRect(x: 0.0, y: 0.0, width: 14.0, height: 14.0)
dot.position = CGPoint(x: 100.0, y: 40.0)
dot.backgroundColor = UIColor(white: 0.8, alpha: 1.0).CGColor
dot.borderColor = UIColor(white: 1.0, alpha: 1.0).CGColor
dot.borderWidth = 1.0
dot.cornerRadius = 2.0r.addSublayer(dot)

创建了一个 14x14 的矩形,圆角半径 2 像素。最后将 dot 层添加到 replicator 中。运行 app 是这个样子:

然后设置 replicator 让它绘制 15 个 dot 并每个旋转 2π/15 度(也就是这个角度乘以 15 构成一个整圆):

let nrDots: Int = 15r.instanceCount = nrDots
let angle = CGFloat(2*M_PI) / CGFloat(nrDots)
r.instanceTransform = CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0)

你将 instanceCount 设置为 15,然后设置一个旋转矩阵变换,旋转 2π/15 弧度。

注意:如果你觉得有点难,请参考 iOS Animations by Tutorials 的 8-11 章关于图层动画,以及 12-14 章关于特殊图层。

运行 app,开始欣赏:

你可以将 nrDots 修改为 10、25 或别的值,简单体验一下你的小菊花。replicator 会忠实地为你计算这形状并显示出来:

现在让这些 dot 每 1.5 秒就进行缩小。创建一个缩放动画,将它应用到第一个 dot 上:

let duration: CFTimeInterval = 1.5let shrink = CABasicAnimation(keyPath: "transform.scale")
shrink.fromValue = 1.0
shrink.toValue = 0.1
shrink.duration = duration
shrink.repeatCount = Float.infinitydot.addAnimation(shrink, forKey: nil)

这会导致一种催眠动画,所有的 dot 都会同步地一遍遍动起来并消失(请自己小心,不要长时间看这个动画)。

希望你还记得要让这个动画动起来,这只需要给每个拷贝加一个延时:

r.instanceDelay = duration/Double(nrDots)

这会让你的动画完美地旋转。只不过动画第一遍循环时有一点奇怪的地方——所有的 dot 一开始都是显示的,只有在第一次循环之后它们才会消失。要解决这个问题,你需要将最初的 dot 在动画开始之前缩小,在 animation2() 最后一句添加:

dot.transform = CATransform3DMakeScale(0.01, 0.01, 0.01)

这样动画就平滑了:

哇,这个动画的创建比想象的简单吧?如果你熟悉了上面的基本进度指示器代码之后,你可以创建轻易创建出各种效果,试试吧!

3. Follow the leader

最后一个最精彩的动画是 Follow the leader。这个动画中你将让你的原始 layer 沿某条路径运动,让它的复制品跟随着它并试图跟上它。

将 viewDidLoad() 方法中的 animation2() 替换为:

animation3()

你应该猜到接下来要添加一个方法了:

func animation3() {}

对于这个动画,你需要的方法不止一个。我会用 PaintCode 快速创建一个贝塞尔路径,然后将这个路径用于动画。在 ViewController 中添加这个方法:

func rw() -> CGPath {Bezier Drawinglet bezierPath = UIBezierPath()bezierPath.moveToPoint(CGPointMake(31.5, 71.5))bezierPath.addLineToPoint(CGPointMake(31.5, 23.5))bezierPath.addCurveToPoint(CGPointMake(58.5, 38.5), controlPoint1: CGPointMake(31.5, 23.5), controlPoint2: CGPointMake(62.46, 18.69))bezierPath.addCurveToPoint(CGPointMake(53.5, 45.5), controlPoint1: CGPointMake(57.5, 43.5), controlPoint2: CGPointMake(53.5, 45.5))bezierPath.addLineToPoint(CGPointMake(43.5, 48.5))bezierPath.addLineToPoint(CGPointMake(53.5, 66.5))bezierPath.addLineToPoint(CGPointMake(62.5, 51.5))bezierPath.addLineToPoint(CGPointMake(70.5, 66.5))bezierPath.addLineToPoint(CGPointMake(86.5, 23.5))bezierPath.addLineToPoint(CGPointMake(86.5, 78.5))bezierPath.addLineToPoint(CGPointMake(31.5, 78.5))bezierPath.addLineToPoint(CGPointMake(31.5, 71.5))bezierPath.closePath()var t = CGAffineTransformMakeScale(3.0, 3.0)return CGPathCreateCopyByTransformingPath(bezierPath.CGPath, &t)!
}

这个方法创建了一个贝塞尔路径并返回一个 CGPath——你将用这个 CGPath 创建一个关键帧动画。

在 animation3() 中添加:

let r = CAReplicatorLayer()
r.bounds = view.bounds
r.backgroundColor = UIColor(white: 0.0, alpha: 0.75).CGColor
r.position = view.centerview.layer.addSublayer(r)

这次你创建了一个和 view controller 的 view 一样大的空的 replicator layer,并将它添加到屏幕上。和之前一样,你首先需要添加第一个 layer 给 replicator 使用:

let dot = CALayer()
dot.bounds = CGRect(x: 0.0, y: 0.0, width: 10.0, height: 10.0)
dot.backgroundColor = UIColor(white: 0.8, alpha: 1.0).CGColor
dot.borderColor = UIColor(white: 1.0, alpha: 1.0).CGColor
dot.borderWidth = 1.0
dot.cornerRadius = 5.0
dot.shouldRasterize = true
dot.rasterizationScale = UIScreen.mainScreen().scaler.addSublayer(dot)

你创建了一个灰色小矩形,圆角半径是宽度的一半,这样它就变成了一个圆形。将这个圆加到 replicator 里。如果运行 app,你会看到在屏幕左上角有一个小圆。

让这个圆点沿路径移动:

let move = CAKeyframeAnimation(keyPath: "position")
move.path = rw()
move.repeatCount = Float.infinity
move.duration = 4.0
dot.addAnimation(move, forKey: nil)

这个动画让圆点沿 rw() 方法产生的路径移动。动画时长为 4 秒,无限循环。

注意:如果你想了解更多关于 layer 用路径进行关键帧动画的内容,请阅读 iOS Animations by Tutorials 第二版的第 15 章“笔触和路径动画”。

运行 app,你将看到圆点疯狂移动但却无法认出它描绘的路径是什么。

让我们将事情变得更明显一点,让 replicator layer 真正发挥作用。添加代码:

r.instanceCount = 20
r.instanceDelay = 0.1

这会添加 19 个拷贝,让他们跟随第一个圆点运动:

好棒!这个动画看起来更像你最爱的 raywenderlich.com 的 Logo。

让我们给圆点加一点绿色,模拟网站的颜色。添加这句给 replicator 的内容上色:

r.instanceColor = UIColor(red: 0.0, green: 1.0, blue: 0.0, alpha: 1.0).CGColor

设置 instanceColor 会在原始内容的颜色上乘以你指定的颜色。这里,我们乘以浅绿色,这样你运行 app 之后你会看到一个很绿的动画:)))

有趣的一点是,你还可以让每个拷贝的 instanceColor 不同。这其实很简单,你可能想让绿色随着每个圆点越来越暗。在最后加上这句:

r.instanceGreenOffset = -0.03

这将使 replicator 将每个圆点的绿色部分递减 0.03。最后的动画效果如下:

我听到有人说:打开一个新 Xcode 项目,开始克隆一个贪吃蛇游戏?:]

这是本月教程中的最后一个动画!如果你认真阅读苹果文档,你会发现 CAReplicatorLayer 的内容很多。在本教程中未涉及的一个主题就是 CAReplicatorLayer 类制自己的动画属性(而不是 content 图层的动画属性)——那完全是另外一个主题了!

如果你用 CAReplicatorLayer 创建了某些漂亮的动画,别忘了 twitt 我 @icanzilb 给我欣赏一下。本文到此结束,别忘了阅读下面的链接!

用 CAReplicatorLayer 创建动画相关推荐

  1. iOS CAReplicatorLayer 简单动画

    代码地址如下: http://www.demodashi.com/demo/11601.html 写在最前面,最近在看学习的时候,偶然间发现一个没有用过的Layer,于是抽空研究了下,本来应该能提前记 ...

  2. 使用Python,OpenCV创建动画GIF图和模因生成器

    在这篇博客中,我们将学习如何使用Python,OpenCV,dlib和ImageMagick工具箱创建动画GIF. 然后,您将结合所有这些技术,使用OpenCV构建一个模因生成器(眼镜

  3. 【Flutter】Animation 动画 ( AnimatedBuilder 动画使用流程 | 创建动画控制器 | 创建动画 | 创建动画作用的组件 | 关联动画与组件 | 动画执行 )

    文章目录 ◯.AnimatedBuilder 引入 一.创建动画控制器 二.创建动画 三.创建动画作用的组件 四.创建 AnimatedBuilder 关联动画与组件 五.动画运行 六.完整代码示例 ...

  4. 【Flutter】Animation 动画 ( AnimatedWidget 动画使用流程 | 创建动画控制器 | 创建动画 | 创建 AnimatedWidget 动画组件 | 动画运行 )

    文章目录 ◯.AnimatedWidget 组件引入 一.创建 AnimatedWidget 动画组件 二.创建动画控制器 三.创建动画 四.动画运行 五.完整代码示例 六.相关资源 Animated ...

  5. 【Flutter】Animation 动画 ( Flutter 动画基本流程 | 创建动画控制器 | 创建动画 | 设置值监听器 | 设置状态监听器 | 布局中使用动画值 | 动画运行 )

    文章目录 一.创建动画控制器 二.创建动画 三.设置值监听器 四.设置状态监听器 五.布局中使用动画值 六.动画运行 七.完整代码示例 八.相关资源 Flutter 动画基本流程 : ① 创建动画控制 ...

  6. Android复习15【动画:创建资源文件夹、创建动画资源文件、组合动画、属性动画、材料设计新特性】

    2020-05-09-[12周-周四] Android动画 https://blog.csdn.net/zhangbijun1230/article/details/80262359 https:// ...

  7. lua cocos 创建动画的几种方式

    lua cocos 创建动画有如下几种方式可供大家选择: 第一种方式: 在cocos studio 中拖进去一个Armature,在Armature的特性一栏导入美术或者自己做好的动画(导入文件). ...

  8. 从Flash到Silverlight进阶教程-用代码来创建动画

    从Flash到Silverlight进阶教程 用代码来创建动画 这节里将要讲述一个自定义用户控件最基本的操作,就好象Flash中的MovieClips一样,动态的将其添加到舞台上. 首先你将要看到如何 ...

  9. Unity 2D教程 | 骨骼动画:创建动画

    转载自:2016-02-13 Unity官方平台 本教程主要讲解Unity引擎自带的2D骨骼动画工具,以及2D动画的基本概念.本篇会添加一些动画,如默认状态.跳动.坠落等. 基础动画理论 制作动画要牢 ...

最新文章

  1. android stadio 打开别人的工程 一直在编译中
  2. 九维 Addon for SBO 功能说明及新版软件下载
  3. PHP(TP5)获取微信小程序unionId
  4. 谈Apache OFbiz 会员模块表结构设计
  5. ios html正则表达式,ios 正则表达式去html标签
  6. 为什么要free释放内存_为什么在Free Code Camp上列出一份工作要花1,000美元?
  7. [转贴]降低网络延迟的方法
  8. python接口自动化(八)--发送post请求的接口(详解)
  9. php mcrypt取消,准备在PHP 7.2中删除Mcrypt
  10. 服务器关机显示正在停止服务,云服务器一直停止中
  11. 计算机组成原理——总线
  12. 到底什么是有限单元法?
  13. 线性代数辅导讲义(第三章 向量)
  14. 伪彩色增强(基于MATLAB)
  15. 兵法三十六计第一计-瞒天过海。
  16. 改wifi密码显示服务器拒绝访问权限,wifi密码对但是拒绝接入? | 192路由网
  17. 【论文笔记】CondConv: Conditionally Parameterized Convolutions for Efficient Inference
  18. babel-plugin-transform-remove-consol插件的安装及使用(作用是移除代码里的所有console.log())
  19. win10怎么放计算机在桌面,win10怎么把此电脑放到桌面_w10如何把此电脑添加到桌面...
  20. 【题解】P3975 [TJOI2015]弦论 后缀自动机

热门文章

  1. 借助CSS Shapes实现元素滚动自动环绕iPhone X的刘海
  2. YOLOv3反向传播原理 之 全流程源码分析
  3. 页面如何手写文字html,html手写代码学习笔记
  4. instell-gnu-acct
  5. 有意思的复活节彩蛋[摘]
  6. 欢迎光临liyuanbicy的博客
  7. 2012第23周国内Android应用下载排行榜动态
  8. 阿里云网站备案时网站无法访问是什么原因及如何解决?
  9. 设计模式读书笔记:Bridge(桥接)
  10. 关于教室派软件使用体验