美文网首页iOS开发iOS开发iOS Developer - Animation
一款Loading动画的实现思路(四·完结篇)

一款Loading动画的实现思路(四·完结篇)

作者: 柯烂 | 来源:发表于2015-12-20 21:26 被阅读3993次

    感谢大家对前几篇的支持,这一篇,我们一鼓作气,把整个动画完成。

    惯例,为了方便第一次来的同学,我先贴一下动画完成的效果图:


    实现阶段4时,我们用了一种处理问题的方式,大约是这样的:

    描述问题,直到足够清晰
    把问题分解成一组小问题
    利用经验处理可以解决的问题
    经验无法解决的问题,我们去调研,调研结果会成为我们下次的经验

    阶段5中,我们再应用一下这个方式(有疑惑的同学可以戳第三篇)。

    先来看一下阶段5的效果图,
    惯例,前几个阶段的动画我们用灰色快速表示,当前阶段使用彩色慢速表示,如图:

    阶段5

    看上去比阶段4还要复杂,别急,我们来描述一下:

    一开始圆是扁的,圆里面有一条粗线,粗线的顶部和圆的顶部连在一起,
    渐渐恢复原状,同时粗线渐渐变长,连到了圆的底部,与此同时,粗线的某处出现了两条线,分别向左下、右下延伸,渐渐连到了圆上。

    很粗糙,但基本上描述出了这个阶段。

    上文中我加黑了部分文字,这些文字很有标志性(有的平台转载时看不到加黑,可以戳原文查看)

    “一开始”,指示出了本阶段动画的初始阶段
    “渐渐”,指示出了动画
    “同时”、“分别”,指示出了本阶段中可以拆分出的子动画

    由此我们可以得到下面的描述:

    初始:
    圆:扁的
    粗线:顶部和圆顶部连着,底部不连着
    左下线:看不到
    右下线:看不到

    动画:
    圆:恢复到正常的形状
    粗线:变长
    左下线:出现并变长
    右下线:出现并变长

    结束:
    圆:正常的形状
    粗线:顶点、底点分别与圆的顶点、底点连着
    左下线:起点在粗线上,终点在圆上
    右下线:起点在粗线上,终点在圆上

    和前面的描述相比,这个描述形式化了,虽然还比较粗略,但已经清晰的标明动画被拆分成了4部分,各部分的初始及结束状态也有了。

    我们给4部分染上不同的颜色看一下:

    阶段5 多彩版

    是不是比之前的清晰多了,
    描述问题分解问题,到这里我们就完成了。

    接下来就是思考动画的方案了:

    圆:阶段4中是执行transform.scale.y动画变扁了,本阶段将transform恢复为CATransform3DIdentity就可以了;
    粗线:阶段4中是从无成长到一定长度,用的stroke方案(想了解stroke方案的同学请戳第二篇),这个阶段就是继续变长,沿用stroke方案就可以了;
    左下线、右下线:本质是一样,从无成长到一定长度,类比粗线可知,可以使用stroke方案;

    这些方案都是以前的经验,阶段5可以不用调研了。

    接下来就是找关键的节点值了:

    对于一个动画来讲,关键的节点就是初始状态和结束状态,前几篇中我们一起找过了关键的节点值,相信大家已经有感觉了,本文我们就不再找了。

    我们一起来看一下阶段5中特殊的地方:

    前文中说到粗线时,我说的是继续变长
    继续听上去就有延续的意思,看上去,粗线两个阶段的动画可以合并成一个。

    回忆一下,阶段4中粗线的path起点是圆未变形时的顶点,终点是圆未变形时的圆心,strokeEnd是从path起点逐渐stroke到path的终点,如下图(灰色是path,蓝色是stroke,SS、SE是初始,SS'、SE'是结束):


    阶段4 粗线

    结合阶段5,我们可以将path的终点修改为圆的底点,这样一来,就将阶段4的strokeEnd修改为从path的起点stroke到path的1/2处,如下图:


    新阶段4 粗线

    而阶段5的strokeEnd就是在阶段4的基础上继续stroke到path的终点,这样两个阶段的动画就合到一起了,如下图:


    阶段5 粗线

    有的同学可能会说,早知道是这样,一开始就这样写就可以了。

    这么说的是有道理的,有的人习惯这样,先分阶段考虑,再整体看一下各阶段,该合并的合并,该修改的修改,方案成形,最后写代码,这是个很好的方式。

    然而对我来说,阶段性的成就感很重要,每当我看到一个阶段的动画在我眼前动起来,感觉都很爽,所以我还是习惯于逐个阶段的实现,有需要时重构前面的阶段,只要逻辑清晰,重构起来问题不大。

    每个人都能找到最适合自己的方式,这本身就是一种乐趣。

    好了,阶段5我们聊了很多,后面的阶段我们就简要的说一下了。
    从完整的效果图可知,这个动画是有成功和失败两个状态的,因此我们分开来看。

    成功状态,从阶段5到阶段6_success:


    阶段6_success

    描述一下:
    圆变色
    对号渐渐出现(stroke)

    失败状态,先是从阶段3直接到阶段6_fail:


    阶段6_fail

    描述一下:
    圆变色
    叹号的上半部分渐渐出现(stroke)
    叹号的下半部分渐渐出现(stroke)

    然后从阶段6_fail到阶段7_fail:


    阶段7_fail

    描述一下:
    叹号绕圆心左右晃几下(rotate)

    阶段7_fail要简单的说一下:

    在阶段6_fail中,叹号被拆分成了上下两个layer,而在阶段7_fail中两者又是作为一个整体动的,我们要让它们分别执行动画么?

    不是的,一个独立的动画应该只涉及一个对象,两个layer有共同的superLayer,让superLayer执行动画就可以了,假如superLayer还有其他subLayer,不方便执行动画,我们在两个layer和superLayer中间插入一层专门执行动画的layer就可以了。

    到这里,我们的动画就完成了,完整代码请移步GitHub上的OneLoadingAnimation工程

    在结束之前,我们简单说一下阶段1另一种思路(想看看阶段1的同学请戳第一篇),这个思路更符合直觉,这个思路是受简友YouXianMing第一篇中的评论启发,感谢。

    先回忆一下阶段1的样子:


    阶段1

    描述一下:
    圆从不完整渐渐变到完整(stroke)
    圆在渐渐旋转(rotate)

    由此我们得出,一个圆同时执行stroke和rotate动画就可以了,下面是示意代码

    // 不完整的示意代码
    - (void)doStep1 {
        // 不用自定义layer了
        self.arcToCircleLayer = [CAShapeLayer layer]; 
    
        // stroke动画
        CABasicAnimation *ssAnima = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
        CABasicAnimation *seAnima = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    
        // rotate动画
        CABasicAnimation *rotateAnima = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    
        // 同时执行
        CAAnimationGroup *animation = [CAAnimationGroup animation];
        animation.animations = @[ssAnima, seAnima, rotateAnima];
    }
    

    是不是比第一篇的实现方式更清晰,
    我们也可以看到,问题分解后,局部的优化也比较方便,
    这部分的完整代码我放到了工程的OneLoadingAnimationStep1Another目录下。

    有的同学还记得,我们这是一个简化的版本,阶段4中原动效中圆的不规则变形被我处理成了规则变形,
    为了思路不被卡住,我选择了暂时简化,完成之后,我们可以再去优化

    为了弥补这个缺憾,我会开一个外篇,专门聊一下圆不规则变形的实现,欢迎大家到时来捧场;

    另,有简友在简信中提到了Swift,因此我写了一个Swift版的实现,放在了工程的OneLoadingAnimationCompleteSwift目录下,由于我的Swift水平不够,代码里还有坑,仅供参考。

    本系列的主线到这就完结了,非常感谢大家的捧场!

    完整代码

    请参考GitHub上OneLoadingAnimation工程

    本系列的�传送门

    鸣谢及推荐

    相关链接

    相关文章

      网友评论

      • 柯烂:是有这个问题 :smiley: ,这个示例主要为了展示思路,应该不止这一个坑,后续我可能会把它做成一个控件,到时把坑填一填 :smile: 希望像你这样认真的同学越来越多
      • 为了自由的白菜:作者我发现一个Bug,不知道算不算Bug,就是重复点击几次,就会出现,你试一下,这个算bug吗?因为正常情况下,加载只需要一次,如果重复加载,就会出现错乱,这种情况不知道在运用中会出现吗?
      • Raybon_lee:我的经理看到了也觉得不错:smile:
        柯烂:@Raybon_lee 感谢两位的鼓励😄
      • sincere_bs:楼主棒棒哒,已关注,期待新作。
        柯烂:@neilbee 谢谢鼓励,会持续更新😄
      • d84469239525:博主棒棒的,作为一个真正喜欢编程的女程序员真心觉得你对待编程的态度还有你对于人生的见解都非常nice
        柯烂:@蓝姬英 谢谢夸奖 :smile: 用心会发现乐趣,不只是编程,& 愿程序媛越来越多
      • SawyerZh:谢谢作者,有空详细拜读
        柯烂:@天路客 谢谢鼓励 :smile:
      • 63772774caa1:结合你的例子,实践了一下,赞
        柯烂:@iOS程序猿 一起进步 :beer:
      • dispath_once:厉害:+1::+1:
        柯烂:@dispath_once 谢谢鼓励 :smile:
      • anly_jun:赞👍
        柯烂:@anly_jun :beer:
      • 曾樑:好玩:smile::smile:
        柯烂:@曾樑 :smile: :smile:

      本文标题:一款Loading动画的实现思路(四·完结篇)

      本文链接:https://www.haomeiwen.com/subject/mpxuhttx.html