【iOS】STLoadingGroup-知乎日报加载动画

jopen 8年前

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

Github :

环境信息:

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

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

三、选择

1.选择作用对象

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

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

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

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

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

2.选择动画

既然选择了 layer,那么动画肯定选择 CA 开头的类。其中 CAAnimation 、 CABasicAnimation 、 CAKeyframeAnimation 等动画都有自己的特点。 因为只需要简单的控制 stokeEnd 与 stokeStart ,所以 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 中,控制这两个点分别是 stokeEnd 和 stokeStart 属性。所以最初终点 stokeEnd = 0 。

2.动画

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

其中,控制两个点的 stokeEnd 和 stokeStart 分别位于:

所以,先对 stokeEnd 进行动画,随后 stokeStart 追上它。这个“随后”怎么处理呢?最直观的就是延迟,设置动画的 beginTime ,但是这里没必要。 stokeStart 和 stokeEnd 的有效值均为 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 * 绘制一圈的时长。

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

来自: http://www.saitjr.com/ios/ios-stloadinggroup-zhihu-load-animation.html

</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span>