Flutter实现动画列表AnimateListView

由于业务需要,在打开列表时,列表项需要一个从右边飞入的动画效果,故封装一个专门可以执行动画的列表组件,可以自定义自己的动画,内置有水平滑动,缩放等简单动画。花里胡哨的动画效果由你自己来定制吧。

功能:

1.可自定义动画。

2.内置水平滑动和缩放动画。

演示:

代码:

import 'dart:math';import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';///可设置动画的列表。
///内部使用的是[SingleChildScrollView]实现,
///需要外层设置定义可约束高度。
class KqAnimateListView<T> extends StatefulWidget {///数据final List<T> data;///列表final Widget Function(T t) item;///动画自定义final IAnimate? animate;///是否需要每次刷新时都执行动画final bool isNeedFlashEveryTime;const KqAnimateListView({super.key,required this.item,required this.data,this.animate,this.isNeedFlashEveryTime = false,});@overrideState<StatefulWidget> createState() => _KqAnimateListViewState<T>();
}class _KqAnimateListViewState<T> extends State<KqAnimateListView<T>>with TickerProviderStateMixin {late IAnimate animate;late AnimationController controller;late Animation animation;@overridevoid initState() {super.initState();animate = widget.animate ?? ScaleAnimate();animate.init(widget.data.length);controller = animate.getAnimationController(this);animation = animate.getAnimation(controller, this);//启动动画(正向执行)controller.forward();}@overridevoid didUpdateWidget(covariant KqAnimateListView<T> oldWidget) {super.didUpdateWidget(oldWidget);if (widget.isNeedFlashEveryTime) {animate = widget.animate ?? ScaleAnimate();animate.init(widget.data.length);controller = animate.getAnimationController(this);animation = animate.getAnimation(controller, this);//启动动画(正向执行)controller.forward();}}@overrideWidget build(BuildContext context) {return SizedBox.expand(child: SingleChildScrollView(child: Column(children: _getChildren(context),),),);}List<Widget> _getChildren(BuildContext context) {List<Widget> list = [];for (int i = 0; i < widget.data.length; i++) {Widget child = widget.item.call(widget.data[i]);list.add(animate.animate(context, i, child, animation, controller),);}return list;}@overridevoid dispose() {controller.dispose();super.dispose();}
}///动画抽象类。
///实现该类,定制自己的列表动画。
abstract class IAnimate {///初始化///[length] 列表长度void init(int length);///获取AnimationControllerAnimationController getAnimationController(TickerProvider provider);///获取AnimationAnimation getAnimation(AnimationController controller, State<StatefulWidget> state);///定制自己的动画,每一个item都会调用到animate,///当需要差异动画时需要根据[index]计算不同item的动画时机///[widget] 执行动画之后的widget///[index] 列表的item的indexWidget animate(BuildContext context,int index,Widget widget,Animation animation,AnimationController controller,);
}///水平移动动画
class HorizontalAnimate extends IAnimate {///动画执行时长比例static double rate = 0.4;///单个动画执行长度static double baseGap = 1000.0;///两个个动画执行间隔长度static double twoGap = 200.0;///动画执行的总长度,根据列表长度动态计算值late double gap;///动画是从左边还是右边开始执行HorizontalAnimateDirection direction;HorizontalAnimate({this.direction = HorizontalAnimateDirection.right});@overridevoid init(int length) {gap = length * twoGap + baseGap;}@overrideWidget animate(BuildContext context, int index, Widget widget,Animation animation, AnimationController controller) {double width = context.width;///范围0->1double mix = (animation.value - twoGap * index) / baseGap;if (mix > 1) {mix = 1;}double left = width * (1 - mix);return Container(transform: Matrix4.translationValues(direction == HorizontalAnimateDirection.left ? -left : left, 0, 0),child: widget,);}@overrideAnimationController getAnimationController(TickerProvider provider) {return AnimationController(duration: Duration(milliseconds: (gap * rate).toInt()),vsync: provider);}@overrideAnimation getAnimation(AnimationController controller, State<StatefulWidget> state) {return Tween(begin: 0.0, end: gap).animate(controller)..addListener(() {if (state.mounted) {state.setState(() {});}});}
}enum HorizontalAnimateDirection {///左边left,///右边right;
}///缩放动画
class ScaleAnimate extends IAnimate {///动画执行时长比例static double rate = 0.4;///单个动画执行长度static double baseGap = 1000.0;///两个个动画执行间隔长度static double twoGap = 200.0;///动画执行的总长度,根据列表长度动态计算值late double gap;@overrideWidget animate(BuildContext context, int index, Widget widget,Animation animation, AnimationController controller) {double width = context.width;///范围0.5->1double mix = ((animation.value - twoGap * index) / baseGap + 1) / 2;if (mix > 1) {mix = 1;}double widthMix = width * mix;return SizedBox(width: max(0, widthMix),child: widget,);}@overrideAnimationController getAnimationController(TickerProvider provider) {return AnimationController(duration: Duration(milliseconds: (gap * rate).toInt()),vsync: provider);}@overrideAnimation getAnimation(AnimationController controller, State<StatefulWidget> state) {return Tween(begin: 0.0, end: gap).animate(controller)..addListener(() {if (state.mounted) {state.setState(() {});}});}@overridevoid init(int length) {gap = length * twoGap + baseGap;}
}

 使用:

                KqAnimateListView(data: const ["Test1","Test2","Test3","Test3","Test3","Test3","Test3","Test3","Test3","Test3","Test3","Test3","Test3"],item: (t) {return Container(width: double.infinity,height: 50,color: Colors.redAccent,margin: EdgeInsets.only(top: 10.r),child: Text(t),);},animate: type == 0? HorizontalAnimate(direction: HorizontalAnimateDirection.left): type == 1? HorizontalAnimate(direction: HorizontalAnimateDirection.right): ScaleAnimate(),isNeedFlashEveryTime: true,)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/86299.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【stable-diffusion使用扩展+插件和模型资源(下)】

插件模型魔法图片等资源&#xff1a;https://tianfeng.space/1240.html 书接上文&#xff1a;&#xff08;上&#xff09; 插件推荐 1.lobe theme lobe theme是一款主题插件&#xff0c;直接可以在扩展安装 界面进行了重新布局&#xff0c;做了一些优化&#xff0c;有兴趣的…

FPGA GTX全网最细讲解,aurora 8b/10b协议,OV5640板对板视频传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、GTX 全网最细解读GTX 基本结构GTX 发送和接收处理流程GTX 的参考时钟GTX 发送接口GTX 接收接口GTX IP核调用和使用 4、设计思路框架视频源选择OV5640摄像头配置及采集动态彩条视频数据组包GTX aurora 8b/10b数据对…

【AndroidStudio】java.nio.charset.MalformedInputException: Input length = 1

java.nio.charset.MalformedInputException: Input length 1 可以参考这个文章处理下编码格式&#xff1a;https://blog.csdn.net/twotwo22222/article/details/124605029java.nio.charset.MalformedInputException: Input length 1是因为你的配置文件里面有中文或者是你的编…

时序预测 | MATLAB实现Attention-GRU时间序列预测(注意力机制融合门控循环单元,TPA-GRU)

时序预测 | MATLAB实现Attention-GRU时间序列预测----注意力机制融合门控循环单元&#xff0c;即TPA-GRU&#xff0c;时间注意力机制结合门控循环单元 目录 时序预测 | MATLAB实现Attention-GRU时间序列预测----注意力机制融合门控循环单元&#xff0c;即TPA-GRU&#xff0c;时…

聚观早报 | 云鲸扫拖机器人J4体验;芯科科技第三代无线开发平台

【聚观365】8月24日消息 云鲸扫拖机器人J4体验 芯科科技推出第三代无线开发平台 英伟达与VMWare宣布扩大合作 万物新生&#xff08;爱回收&#xff09;2023年二季度财报 充电桩需求增长带动汽车后服务市场 云鲸扫拖机器人J4体验 家庭卫生清洁是每个人都无法回避的事情&am…

路径规划 | 图解Theta*算法(附ROS C++/Python/Matlab仿真)

目录 0 专栏介绍1 A*算法的局限性2 Theta*算法原理图解3 Bresenham视线法4 算法仿真测试4.1 算法流程图4.2 ROS C 实现4.3 Python实现4.4 Matlab实现 0 专栏介绍 &#x1f525;附C/Python/Matlab全套代码&#x1f525;课程设计、毕业设计、创新竞赛必备&#xff01;详细介绍全…

Elasticsearch中倒排索引、分词器、DSL语法使用介绍

&#x1f353; 简介&#xff1a;java系列技术分享(&#x1f449;持续更新中…&#x1f525;) &#x1f353; 初衷:一起学习、一起进步、坚持不懈 &#x1f353; 如果文章内容有误与您的想法不一致,欢迎大家在评论区指正&#x1f64f; &#x1f353; 希望这篇文章对你有所帮助,欢…

Go语言入门记录:从基础到变量、函数、控制语句、包引用、interface、panic、go协程、Channel、sync下的waitGroup和Once等

程序入口文件的包名必须是main&#xff0c;但主程序文件所在文件夹名称不必须是main&#xff0c;即我们下图hello_world.go在main中&#xff0c;所以感觉package main写顺理成章&#xff0c;但是如果我们把main目录名称改成随便的名字如filename也是可以运行的&#xff0c;所以…

Python采集关键词结果辅助写作

大家好&#xff01;在进行学术研究和 写作时&#xff0c;获取准确、全面的文献资料和相关研究成果是非常重要的。在本文中&#xff0c;我将与你分享使用Python爬虫 采集 学术关键词结果来辅助 写作的方法&#xff0c;帮助你快速获取与研究主题相关的学术文献和 。 **1. 设置搜索…

SqlServer2019—解决SQL Server 无法连接127.0.0.1的问题

1、打开SQL Server 2019配置管理器 2、SQL Servere 网络配置(启用 Named Pipes 和 TCP/IP) 3、修改TCP/IP协议(右键选择属性—IP地址)&#xff0c;具体如下图所示&#xff1a; 4、重启SQL Server服务

LLMs参数高效微调(PEFT) Parameter efficient fine-tuning (PEFT)

正如你在课程的第一周所看到的&#xff0c;训练LLMs需要大量的计算资源。完整的微调不仅需要内存来存储模型&#xff0c;还需要在训练过程中使用的各种其他参数。 即使你的计算机可以容纳模型权重&#xff0c;最大模型的权重现在已经达到几百GB&#xff0c;你还必须能够为优化…

Blender给一个对象添加多个动画

最近在做一个类似元宇宙的项目&#xff0c;需要使用3D建模软件来给3D模型添加动画&#xff0c;3D建模软件选择Blender&#xff08;因为开源免费…&#xff09;&#xff0c;版本: V3.5 遇到的需求是同一个对象要添加多个动画&#xff0c;然后在代码里根据需要调取动画来执行。本…