加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

用 CAReplicatorLayer 创建动画

发布时间:2020-12-14 06:01:18 所属栏目:百科 来源:网络整理
导读:原文:Creating animations with CAReplicatorLayer 作者:Marin Todorov 译者:kmyhy 本教程针对 Xcode 7/Swift 2 或更高版本。 CAReplicatorLayer 绝对是我最爱的 CALayer,因此我很愿意向你介绍如何用它来创建动画。 在本教程中,我将向你展示用 CAReplic

原文: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,width: 8.0,height: 40.0)
bar.position = CGPoint(x: 10.0,y: 75.0)
bar.cornerRadius = 2.0
bar.backgroundColor = UIColor.redColor().CGColor

r.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.infinity

bar.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,width: 200.0,height: 200.0)
r.cornerRadius = 10.0
r.backgroundColor = UIColor(white: 0.0,alpha: 0.75).CGColor
r.position = view.center

view.layer.addSublayer(r)

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

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

let dot = CALayer()
dot.bounds = CGRect(x: 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.0

r.addSublayer(dot)

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

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

let nrDots: Int = 15

r.instanceCount = nrDots
let angle = CGFloat(2*M_PI) / CGFloat(nrDots)
r.instanceTransform = CATransform3DMakeRotation(angle,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.5

let shrink = CABasicAnimation(keyPath: "transform.scale")
shrink.fromValue = 1.0
shrink.toValue = 0.1
shrink.duration = duration
shrink.repeatCount = Float.infinity

dot.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 Drawing
    let 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,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.center

view.layer.addSublayer(r)

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

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

r.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 给我欣赏一下。本文到此结束,别忘了阅读下面的链接!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读