基于Flutter制作一个吃豆人加载动画
作者:老李code 发布时间:2022-12-14 02:55:46
标签:Android,Flutter,吃豆人,加载动画
效果图
国际惯例,先看效果图:
具体效果就是吃豆人会根据吃不同颜色的豆子改变身体的颜色。
绘制静态吃豆人、豆豆、眼睛
首先,我们需要将这个静态的吃豆人绘制出来,我们可以把吃豆人看做是一个实心圆弧,豆豆和眼睛就是一个圆。
关键代码:
//画头
_paint
..color = color.value
..style = PaintingStyle.fill;
var rect = Rect.fromCenter(
center: Offset(0, 0), width: size.width, height: size.height);
/// 起始角度
var a = 40 / 180 * pi;
// 绘制圆弧
canvas.drawArc(rect, 0, 2 * pi - a * 2, true, _paint);
// 画豆豆
canvas.drawOval(
Rect.fromCenter(
center: Offset(
size.width / 2 +
ddSize -
angle2.value * (size.width / 2 + ddSize),
0),
width: ddSize,
height: ddSize),
_paint..color = color2.value);
//画眼睛
canvas.drawOval(
Rect.fromCenter(
center: Offset(0, -size.height / 3), width: 8, height: 8),
_paint..color = Colors.black87);
动画属性: 嘴巴的张合:通过圆弧的角度不断改变实现,豆豆移动:从头的右侧源源不断的有豆子向左移动,改变豆豆x轴的坐标即可,接下来我们让吃豆人动起来吧。
加入动画属性
这里我们需要创建2个动画控制器,一个控制头,一个控制豆豆,我们看到因为头部一开一合属于动画正向执行一次然后再反向执行一次,相当于执行了两次,豆豆的从右边到嘴巴只执行了一次,所以头的执行时间是豆豆执行时间的两倍,嘴巴一张一合才能吃豆子嘛,吃豆完毕,将豆子颜色赋值给头改变颜色,豆子随机获取另一个颜色,不断的吃豆。 这里的绘制状态有多种情况,嘴巴的张合、豆子的平移、颜色的改变都需要进行重新绘制,这里我们可以使用 Listenable.merge
方法来进行监听,接受一个Listenable
数组,可以将我们需要改变的状态放到这个数组里,返回一个 Listenable
赋值给CustomPainter
构造函数repaint
属性即可,然后在监听只需判断这个Listenable
即可。
factory Listenable.merge(List<Listenable?> listenables) = _MergingListenable;
关键代码: 动画执行相关。
late Animation<double> animation; // 吃豆人
late Animation<double> animation2; // 豆豆
late AnimationController _controller = AnimationController(
vsync: this, duration: Duration(milliseconds: 500)); //1s
late AnimationController _controller2 = AnimationController(
vsync: this, duration: Duration(milliseconds: 1000)); //2s
//初始化吃豆人、豆豆颜色
ValueNotifier<Color> _color = ValueNotifier<Color>(Colors.yellow.shade800);
ValueNotifier<Color> _color2 =
ValueNotifier<Color>(Colors.redAccent.shade400);
// 动画轨迹
late CurvedAnimation cure = CurvedAnimation(
parent: _controller, curve: Curves.easeIn); // 动画运行的速度轨迹 速度的变化
@override
void initState() {
super.initState();
animation = Tween(begin: 0.2, end: 1.0).animate(_controller)
..addStatusListener((status) {
// dismissed 动画在起始点停止
// forward 动画正在正向执行
// reverse 动画正在反向执行
// completed 动画在终点停止
if (status == AnimationStatus.completed) {
_controller.reverse(); //反向执行 100-0
} else if (status == AnimationStatus.dismissed) {
_color.value = _color2.value;
// 获取一个随机彩虹色
_color2.value = getRandomColor();
_controller.forward(); //正向执行 0-100
// 豆子已经被吃了 从新加载豆子动画
_controller2.forward(from: 0); //正向执行 0-100
}
});
animation2 = Tween(begin: 0.2, end: 1.0).animate(_controller2);
// 启动动画 正向执行
_controller.forward();
// 启动动画 0-1循环执行
_controller2.forward();
// 这里这样重复调用会导致两次动画执行时间不一致 时间长了就不对应了
// _controller2.repeat();
}
@override
void dispose() {
_controller.dispose();
_controller2.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Center(
child: CustomPaint(
size: Size(50, 50),
painter: Pain2Painter(
_color,
_color2,
animation,
animation2,
Listenable.merge([
animation,
animation2,
_color,
]),
ddSize: 8),
));
}
// 获取一个随机颜色
Color getRandomColor() {
Random random = Random.secure();
int randomInt = random.nextInt(6);
var colors = <Color>[
Colors.red,
Colors.orange,
Colors.yellow,
Colors.green,
Colors.blue,
Colors.indigo,
Colors.purple,
];
Color color = colors[randomInt];
while (color == _color2.value) {
// 重复再选一个
color = colors[random.nextInt(6)];
}
return color;
}
绘制吃豆人源码:
class Pain2Painter extends CustomPainter {
final ValueNotifier<Color> color; // 吃豆人的颜色
final ValueNotifier<Color> color2; // 豆子的的颜色
final Animation<double> angle; // 吃豆人
final Animation<double> angle2; // 豆
final double ddSize; // 豆豆大小
final Listenable listenable;
Pain2Painter(
this.color, this.color2, this.angle, this.angle2, this.listenable,
{this.ddSize = 6})
: super(repaint: listenable);
Paint _paint = Paint();
@override
void paint(Canvas canvas, Size size) {
canvas.clipRect(Offset.zero & size);
canvas.translate(size.width / 2, size.height / 2);
// 画豆豆
canvas.drawOval(
Rect.fromCenter(
center: Offset(
size.width / 2 +
ddSize -
angle2.value * (size.width / 2 + ddSize),
0),
width: ddSize,
height: ddSize),
_paint..color = color2.value);
//画头
_paint
..color = color.value
..style = PaintingStyle.fill;
var rect = Rect.fromCenter(
center: Offset(0, 0), width: size.width, height: size.height);
/// 起始角度
/// angle.value 动画控制器的值 0.2~1 0是完全闭合就是 起始0~360° 1是完全张开 起始 40°~ 280° 顺时针
var a = angle.value * 40 / 180 * pi;
// 绘制圆弧
canvas.drawArc(rect, a, 2 * pi - a * 2, true, _paint);
//画眼睛
canvas.drawOval(
Rect.fromCenter(
center: Offset(0, -size.height / 3), width: 8, height: 8),
_paint..color = Colors.black87);
canvas.drawOval(
Rect.fromCenter(
center: Offset(-1.5, -size.height / 3 - 1.5), width: 3, height: 3),
_paint..color = Colors.white);
}
@override
bool shouldRepaint(covariant Pain2Painter oldDelegate) {
return oldDelegate.listenable != listenable;
}
}
至此,一个简单的吃豆人加载Loading就完成啦。再也不要到处都是菊花转的样式了。。。
来源:https://juejin.cn/post/7088268036804706318


猜你喜欢
- 上周工作中遇到一个奇怪的问题,解决之后想想还是写出来和大家分享一下。故障描述:在A程序中使用Process.Start方法调用一个B.exe
- 本文实例讲述了Android编程之菜单实现方法。分享给大家供大家参考,具体如下:菜单是许多应用程序不可或缺的一部分,Android中更是如此
- 题目要求思路:模拟Javaclass Solution { public int maximumSwap(int
- 一、时区的基本概念GMT(Greenwich Mean Time),即格林威治标准时,是东西经零度的地方。人们将地球人为的分为24等份,每一
- 前言本文详细介绍如何使用spring-boot2.x快速整合log4j2日志框架。spring-boot2.x使用logback作为默认日志
- 面试题1:谈一下你对 Nginx 的理解Nginx 是一款自由的、开源的、高性能的 HTTP 服务器和反向代理服务器;同时也是一个 IMAP
- 本文实例讲述了C#实现类似新浪微博长URL转短地址的方法。分享给大家供大家参考。具体如下:一、前台判断用户输入URL的JS代码如下。func
- C# 8.0中的模式匹配相对C# 7.0来说有了进一步的增强,对于如下类:class Point{ public
- java随机验证码生成实现实例代码摘要: 在项目中有很多情况下都需要使用到随机验证码,这里提供一个java的随机验证码生成方案,可以指定难度
- 实现效果:注意:using system.io; 往Form1上添加控件picturebox,再添加imagelist,并设置imageli
- 本文为大家分享了Java多线程实现Runnable方式的具体方法,供大家参考,具体内容如下(一)步骤 1.定义实现Runnable
- 本文实例讲述了C#推送信息到APNs的方法。分享给大家供大家参考。具体实现方法如下:class Program{ public
- 本文实例为大家分享了Java操作MongoDB模糊查询和分页查询,供大家参考,具体内容如下模糊查询条件:1、完全匹配Pattern patt
- 前言上一篇:微服务网关Zuul上文中,我们介绍了微服务网关Zuul,Zuul 是 Netflix 公司开源的产品,被称为第一代网关,也是 S
- JDK * ,代理接口没有实现类,实现 * JDK代理,代理的是接口,那么笔者想一想,既然代理的是接口,那如果没有实现类怎么办,能不能代
- 一、tomcat内存设置问题 收藏 在使用Java程序从数据库中查询大量的数据或是应用服务器(如tomcat、jboss,weblogic)
- 元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四种。1. Annotation型
- 函数指针基础:1. 获取函数的地址2. 声明一个函数指针3.使用函数指针来调用函数获取函数指针:函数的地址就是函数名,要将函数作为参数进行传
- 说起空间动态、微博的点赞效果,网上也是很泛滥,各种实现与效果一大堆。而详细实现的部分,讲述的也是参差不齐,另一方面估计也有很多大侠也不屑一顾
- 本文实例为大家分享了Java使用单链表实现约瑟夫环的具体代码,供大家参考,具体内容如下构建一个单向的环形链表思路1.先创建第一个节点, 让f