[iOS 动画]实现一个Material Design风格的Loading

难度:⭐️
最终效果:

最终效果
最终效果

平时在逛一些设计相关网站时总想把一些效果实现一下,这次挑了 Google Material Design的练一下手。

我们可以把动画简单地分解为 路径填充 + 旋转:

没有旋转的情况下
没有旋转的情况下

仔细考虑一番,可以发现用改变 CAShapeLayer 的 strokeStart 和 strokeEnd 实现。整个填充看起来像 strokeEnd跑的快, strokeStart开始跑得慢,但在 strokeEnd跑到终点后突然加速追赶。
但似乎时间函数没那么好控制,因为它显得不那么规律。在这种情况下,我们可以使用关键帧动画实现这种不规则的时间函数控制。我简单地把它分为了三个时间点: 0,0.5,1.0。
时间点 0:strokeEnd出发了一点点,但 strokeEnd还没动。
时间点 0.5:strokeEnd已经跑到了终点,strokeEnd才跑了一点距离。
时间点 1.0:strokeEnd在终点等着,strokeStart加速赶到了终点。
经过此番分析后,动画相关的代码大致如下:

let strokeDuration:Double = 2
func strokeStartAnimation() -> CAKeyframeAnimation {
    let animation = CAKeyframeAnimation(keyPath: "strokeStart")
    animation.keyTimes = [0, 0.5, 1]
    animation.values = [0, 0.3, 1]
    animation.duration = strokeDuration
    animation.fillMode = kCAFillModeForwards
    animation.repeatCount = Float.infinity
    return animation
  }
  
  func strokeEndAnimation() -> CAKeyframeAnimation {
    let animation = CAKeyframeAnimation(keyPath: "strokeEnd")
    animation.keyTimes = [0, 0.5, 1]
    animation.values = [0.05, 1, 1]
    animation.duration = strokeDuration
    animation.fillMode = kCAFillModeForwards
    animation.repeatCount = Float.infinity
    return animation
  }

把这两个动画加到了图层上,就能看到没有旋转情况下的效果。再完善一下,添加一个比路径填充稍微慢一点的旋转动画,就能达到文初那种似乎不规则的 loading效果。

不足之处:在路径动画一次结束后切换下一次时感觉没那么过渡自然,那是因为使用路径填充实现。如果使用改变路径长度实现会更好一点(CSS中就可以通过 stroke dash array/offset修改填充长度实现),但在 iOS中,CAShapeLayer的 lineDashPattern 不是 animatable的,导致不能按照 CSS的思路去实现。

其实可以自定义绘制,不过稍显麻烦,如果你追求 pixel perfect,那就那么做吧。

-EOF-

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 的确,听说他要来时,心里是欣喜的。而另外一层理智也反复强调着,这不可能。潜意识里也是觉得,除非脑子瓦特掉了,...
    昼夜思阅读 316评论 0 1
  • 我只愿意关注痛苦中的人。因为我自己经历过,所以才会理解对方是什么状态。我希望彼此可以开心的在人间自由自在的行...
    静如初夏阅读 689评论 0 2
  • 闭月羞花之貌,沉鱼落雁之容,短短十二个字,饱含人们对古代四大美女绝世容颜的赞誉。时光流转,美人随风而去,我们只能在...
    亭殿阁阅读 442评论 0 6