Flutter 动画集锦之小企鹅跑啊跑
highlight: agate
theme: qklhk-chocolate
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第9天,点击查看活动详情
从上一次给大家介绍了自定义单组件布局之后,一直都想写一个关于使用单组件自定义动画的文章. 不过,因为一直没有好的题材,暂且搁置了.今天和对象聊天的时候偶尔发现一个很有意思的动画准备实现一下
起因
这次想做的动画是和对象聊天的时候.对方发的一个表情
相信这个表情很多人应该在wx中也发过, 小企鹅跑来跑去的非常有意思.今天我们就通过 CustomSingleChildLayout 来实现这个动画.
分析
首先我们先分析一下这张图的一个构成.简单来说,就是一个 不规则的图形在来回上下的左右反复运动. 更深入来看, 小企鹅在 移动过程中手的方向也会随移动方向发生改变 . 但是仔细看, 你会发现, 这实际上是x轴反转的一个镜像.
知道这些基本点后, 我们就可以开始设计我们的动画了~
Coding
准备
- 一张透明图片
ps: 这次演示使用的是一张360*360的图片 - 前置教程
如果你发现过程中感觉有些迷茫的话, 不妨静下心先阅读一下关于自定义布局的讲解部分.
Flutter 玩转自定义布局之单组件布局
正篇
绘制背景
首先, 我们创建一个居中的100*200的黄色背景
1 | Scaffold( |
绘制小企鹅
在Container 内部创建一个CustomSingleChildLayout , 由于外部已经给了限制, 我们这里不需要额外通过_DemoSingleDelegate 的 getSize(BoxConstraints constraints) 去给外部约束尺寸. 同时, 我们创建一个Image 来加载需要的图片. 如果你有自己喜欢的图片, 也可以自行加载, 值得注意的是, 你也需要和本文一样使用一张正方形图片,否则需要根据图片大小自行适配下. 为了方便后面的计算. 我们在 _DemoSingleDelegate 中, 重写getConstraintsForChild(BoxConstraints constraints) 的方法, 返回值为BoxConstraints.tight(Size(100, 100)) . 这样便可以将小企鹅约束在100*100 的范围内.
1 | CustomSingleChildLayout( |
效果
小企鹅动起来
在小企鹅绘制到方块中后, 我们怎么让它动起来呢? 这里需 借助AnimationController, 它的作用主要是推动小企鹅运动. 我们知道 AnimationController 有个repeat属性, 天然解决了小企鹅在运动中需要来回奔跑的问题.
1 | AnimationController controller = |
那么, 如何控制小企鹅的位置呢? 我们可以通过 AnimationController 使用动画器Animation, Animattion可以自定义动画的取值和范围. 这里我们先创建一个Animation
1 | /// 用来记录小企鹅的位移 |
创建Animation 之后, 我们发现它内部提供了一个 transform(double t) 的方法. 这里的 t 即 AnimationController的value, 也就是当前动画执行的进度. 我们根据进度来反推小企鹅的位置. 实际上小企鹅的位置很像函数中的正弦函数
我们如果按正常的正弦函数的话 实际上我们只有上下移动一次. 正弦的公式是 y = A sin(Bx + C) + D. 周期的计算公式是 2π/B . 也就是说我们 B 越大, 同时间内,周期越短,上下移动的频次就越高. 我们以 B 等于 6 为例:
其中,蓝色为 B 等于 1 的时候,红色为 B 等于 6 的时候. 我们同时间内可以上下移动 6 次, 了解到了这一点后. 我们就可以根据 AnimationController的value 来计算小企鹅相应的位置了.
1 | // 由于小企鹅左右还有空白的部分,我们实际计算中还要减去这部分. |
计算好小企鹅的位置后, 我们就要同步自定义布局的_DemoSingleDelegate . 我们把 Animation 传入_DemoSingleDelegate .
1 | Animation<_DemoInfo>? animation; |
这样当动画执行时, 我们就可以同步更新画布了. 让我们来看看小企鹅跑起来什么样吧!
小企鹅转向
我们发现在运动过程中,小企鹅并不会在走到头的时候转向. 反转的本质是对小企鹅的x轴反转, 我们来实现一下.
1 | AnimatedBuilder( |
效果
完善界面
小企鹅转向后, 我们发现小企鹅的脚是超出色块的. 这个需要我们手动裁切一下, 我们在 CustomSingleChildLayout 外加上一个ClipRect 就可以啦!
源码
github.com/weniner/flutter_demo/
结语
这里是WeninerIo,热爱生活且热爱旅行.如果你对这次的分享感兴趣又或者有什么疑惑, 不妨评论区留言 + 关注.期待下一次更好的相遇.