『STLoadingGroup』知乎日报加载动画

这段时间在看 ray 的 《iOS Animation by Tutorials》 这本书,把以前完全不熟悉的动画学习了下。然后动手尝试了一些简单的加载动画。本文总结一基础动画的分析过程和实现。

Github :

https://github.com/saitjr/STLoadingGroup

环境信息:

Mac OS X 10.11.2

Xcode 7.2

iOS 9.2

Swift 2

正文:

一、慢动作效果

二、拆分与组合

动画一共可以拆分成三个部分:

  1. 白线开始绘制,逐渐形成圆(aniamtion-1
  2. 白线的起始点变化,追上之前绘制的线,圆环逐渐消失(animation-2
  3. 每次出现的起点顺时针旋转了 1/4 个圆(animation-3

这三个动画的共同点:

  1. animation-1animation-2duration 相同(如果一定要纠结,其实看到的效果 animation-2 应该会比 animation-1 后执行,因为 animation-2 是快速追上 animation-1 的,但这可以通过设置 CABasicAnimationfromValue 来处理成同时执行,详见 《iOS Animation by Tutorials》的 Chapter 15 Stoke and Path Animations )。

  2. 三个动画 repeatCount 相同。都是无限循环,可以将 repeatCount 设置为 Float.infinity 来达到效果。
  3. 执行动画的对象相同,均作用在同一个 layer。

三、选择

1.选择作用对象

关于选用 UIViewCALayer 还是 CAShapeLayer ,首先需要清楚他们的特点和当前需求的符合度。

需求:根据上面的分析,我们需要对象有以下特点:

  • 圆环起点和终点的控制,需要用到 stokeEndstokeStart 属性。
  • 不需要响应用户交互事件。

  • 需要设置线宽、背景色、线头尾的圆角样式。

虽然使用 UIViewdarwRect 方法也能达到效果。但是 UIView 为 layer 的管理者,并且可以捕捉事件(当然这只是其中一个特点)。这一特点我们明显不需要。所以,选择 CAShapeLayer 来实现。

2.选择动画

既然选择了 layer,那么动画肯定选择 CA 开头的类。其中 CAAnimationCABasicAnimationCAKeyframeAnimation 等动画都有自己的特点。 因为只需要简单的控制 stokeEndstokeStart ,所以 CABasicAnimation 已经能满足要求。

四、实现

1.绘制圆环路径

cycleLayer.lineCap = kCALineCapRound // 设置圆角
cycleLayer.lineJoin = kCALineJoinRound // 设置圆角
cycleLayer.lineWidth = STConfiguration.LineWidth // LineWidth 是提前定义的线宽常量
cycleLayer.fillColor = UIColor.clearColor().CGColor
cycleLayer.strokeColor = STConfiguration.MainColor.CGColor // MainColor 是提前定义的主题色常量
cycleLayer.strokeEnd = 0
layer.addSublayer(cycleLayer)

以上代码分别设置了圆环 layer 的圆角、线宽、填充色(透明)、边框色( MainColor)、初始化终点位置。

对于一条线的绘制,需要的就是起点和终点。iOS 中,控制这两个点分别是 stokeEndstokeStart 属性。所以最初终点 stokeEnd = 0

2.动画

先来看看更改起点和终点动画的慢动作效果,然后再根据之前的分析,做动画。

其中,控制两个点的 stokeEndstokeStart 分别位于:

所以,先对 stokeEnd 进行动画,随后 stokeStart 追上它。这个“随后”怎么处理呢?最直观的就是延迟,设置动画的 beginTime ,但是这里没必要。stokeStartstokeEnd 的有效值均为 0 ~ 1, 所以,想要有延迟的效果,将动画的 fromValue 设置为负值开始即可。具体负多少,就要看 stokeStart 什么时候追上 stokeEnd 了。

let strokeStartAnimation = CABasicAnimation(keyPath: "strokeStart")
strokeStartAnimation.fromValue = -1
strokeStartAnimation.toValue = 1.0

let strokeEndAnimation = CABasicAnimation(keyPath: "strokeEnd")
strokeEndAnimation.fromValue = 0
strokeEndAnimation.toValue = 1.0

let animationGroup = CAAnimationGroup()
animationGroup.duration = STConfiguration.AnimationDuration // 动画时长是提前定义的常量
animationGroup.repeatCount = Float.infinity
animationGroup.animations = [strokeStartAnimation, strokeEndAnimation]
cycleLayer.addAnimation(animationGroup, forKey: "animationGroup")

最后,是旋转动画。在画线的过程中,同时也在做旋转,所以每次 stokeStart 开始的地方才改变了。再来看一下效果:

let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0
rotateAnimation.toValue = M_PI * 2
rotateAnimation.repeatCount = Float.infinity
rotateAnimation.duration = STConfiguration.AnimationDuration * 4
cycleLayer.addAnimation(rotateAnimation, forKey: "rotateAnimation")

圆环绘制一圈,要变 1/4 个角度,所以, 旋转一圈需要 4 * 绘制一圈的时长。

到此,这个动画最关键的部分就完成了。其他逻辑下载源码进行查看 :

https://github.com/saitjr/STLoadingGroup

《『STLoadingGroup』知乎日报加载动画》有1个想法

发表评论

电子邮件地址不会被公开。