敞开成长之旅!这是我参加「日新方案 12 月更文应战」的第9天,点击检查活动详情
从上一次给咱们介绍了自定义单组件布局之后,一向都想写一个关于运用单组件自定义动画的文章. 不过,因为一向没有好的体裁,暂时搁置了.今天和目标谈天的时分偶然发现一个很有意思的动画准备完成一下
原因
这次想做的动画是和目标谈天的时分.对方发的一个表情
信任这个表情很多人应该在wx中也发过, 小企鹅跑来跑去的十分有意思.今天咱们就经过 CustomSingleChildLayout 来完成这个动画.
剖析
首要咱们先剖析一下这张图的一个构成.简单来说,便是一个 不规则的图形在来回上下的左右反复运动. 更深化来看, 小企鹅在 移动过程中手的方向也会随移动方向发生改动 . 但是仔细看, 你会发现, 这实际上是x轴回转的一个镜像.
知道这些基本点后, 咱们就能够开始规划咱们的动画了~
Coding
准备
- 一张通明图片
ps: 这次演示运用的是一张360*360的图片
- 前置教程
假如你发现过程中感觉有些迷茫的话, 无妨静下心先阅读一下关于自定义布局的讲解部分. Flutter 玩转自定义布局之单组件布局
正篇
制作布景
首要, 咱们创立一个居中的100*200的黄色布景
Scaffold(
body: Center(
child: Container(
color: Colors.yellow,
height: 100,
width: 200,
),
),
);
制作小企鹅
在Container 内部创立一个CustomSingleChildLayout , 因为外部现已给了限制, 咱们这儿不需求额定经过_DemoSingleDelegate 的 getSize(BoxConstraints constraints) 去给外部束缚尺寸. 一起, 咱们创立一个Image 来加载需求的图片. 假如你有自己喜爱的图片, 也能够自行加载, 值得注意的是, 你也需求和本文相同运用一张正方形图片,否则需求依据图片大小自行适配下. 为了便利后边的核算. 咱们在 _DemoSingleDelegate 中, 重写getConstraintsForChild(BoxConstraints constraints) 的方法, 返回值为BoxConstraints.tight(Size(100, 100)) . 这样便能够将小企鹅束缚在100*100 的范围内.
CustomSingleChildLayout(
delegate: _DemoSingleDelegate(),
child: Image.asset(
'assets/images/qiuqiu.png',
height: 100,
width: 100,
),
),
效果
小企鹅动起来
在小企鹅制作到方块中后, 咱们怎么让它动起来呢? 这儿需 凭借AnimationController, 它的作用主要是推动小企鹅运动. 咱们知道 AnimationController 有个repeat属性, 天然解决了小企鹅在运动中需求来回奔跑的问题.
AnimationController controller =
AnimationController(vsync: this, duration: const Duration(seconds: 1));
/// 重复运动
controller.repeat(reverse: true);
那么, 如何控制小企鹅的方位呢? 咱们能够经过 AnimationController 运用动画器Animation, Animattion能够自定义动画的取值和范围. 这儿咱们先创立一个Animation
/// 用来记录小企鹅的位移
class _DemoInfo {
double x;
double y;
_DemoInfo(this.x, this.y);
}
class _DemoAnimation extends Animatable<_DemoInfo> {
@override
_DemoInfo transform(double t) {
...
}
}
创立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 来核算小企鹅相应的方位了.
// 因为小企鹅左右还有空白的部分,咱们实际核算中还要减去这部分.
// 因而x轴要从-25开始核算, y轴咱们能够自定义初始的高度, 然后
// 改动振幅,也便是公式中的A. 这样咱们上下偏移的间隔别离便是10.
return _DemoInfo(-25 + 150.0 * t, 30 + 10 * sin(t * 6 * pi));
核算好小企鹅的方位后, 咱们就要同步自定义布局的_DemoSingleDelegate . 咱们把 Animation 传入_DemoSingleDelegate .
Animation<_DemoInfo>? animation;
_DemoSingleDelegate({required this.animation}) : super(relayout: animation);
这样当动画执行时, 咱们就能够同步更新画布了. 让咱们来看看小企鹅跑起来什么样吧!
小企鹅转向
咱们发现在运动过程中,小企鹅并不会在走到头的时分转向. 回转的本质是对小企鹅的x轴回转, 咱们来完成一下.
AnimatedBuilder(
builder: (BuildContext context, Widget? child) {
return Transform.scale(
/// 这儿当动画forward运行时,小企鹅往左跑. 在reverse时, 小企鹅右跑
scaleX:animation.status == AnimationStatus.forward ? 1 : -1,
child: child,
);
},
animation: animation,
child: Image.asset(
'assets/images/qiuqiu.png',
height: 100,
width: 100,
),
),
效果
完善界面
小企鹅转向后, 咱们发现小企鹅的脚是超出色块的. 这个需求咱们手动裁切一下, 咱们在 CustomSingleChildLayout 外加上一个ClipRect 就能够啦!
源码
github.com/weniner/flu…
结语
这儿是WeninerIo,酷爱生活且酷爱游览.假如你对这次的分享感兴趣又或者有什么疑惑, 无妨评论区留言 + 重视.期待下一次更好的相遇.