求Flutter环境下带计时器的动画列表实现逻辑
带计时器的动画列表实现逻辑(Flutter)
核心思路
每个列表项独立维护倒计时状态,通过计时器驱动剩余时间更新,配合Flutter动画组件实现列表项的进入/退出动画,同时做好计时器与动画控制器的生命周期管理,避免内存泄漏。
具体实现步骤
1. 定义数据模型
创建包含任务信息、倒计时时长、剩余时间及运行状态的模型类:
class TimerItem { final String title; final int totalSeconds; int remainingSeconds; bool isRunning; TimerItem({ required this.title, required this.totalSeconds, required this.isRunning, }) : remainingSeconds = totalSeconds; }
2. 计时器状态管理
在StatefulWidget中维护任务列表与计时器集合,实现启动、暂停、停止计时器的逻辑:
class TimerListPage extends StatefulWidget { const TimerListPage({super.key}); @override State<TimerListPage> createState() => _TimerListPageState(); } class _TimerListPageState extends State<TimerListPage> with TickerProviderStateMixin { late List<TimerItem> _timerItems; final Map<int, Timer> _timers = {}; late List<AnimationController> _animationControllers; @override void initState() { super.initState(); // 初始化示例数据 _timerItems = [ TimerItem(title: "任务1", totalSeconds: 60, isRunning: true), TimerItem(title: "任务2", totalSeconds: 120, isRunning: false), ]; // 初始化动画控制器 _animationControllers = _timerItems.map((_) => AnimationController( vsync: this, duration: const Duration(milliseconds: 300), )).toList(); // 启动已标记为运行的计时器 _startRunningTimers(); } // 启动单个计时器 void _startTimer(int index) { if (_timers.containsKey(index)) return; _timers[index] = Timer.periodic(const Duration(seconds: 1), (timer) { setState(() { if (_timerItems[index].remainingSeconds > 0) { _timerItems[index].remainingSeconds--; } else { _timerItems[index].isRunning = false; timer.cancel(); _timers.remove(index); // 触发结束动画 _handleTimerEnd(index); } }); }); } // 批量启动运行状态的计时器 void _startRunningTimers() { for (int i = 0; i < _timerItems.length; i++) { if (_timerItems[i].isRunning) { _startTimer(i); } } } // 处理倒计时结束逻辑 void _handleTimerEnd(int index) { _animationControllers[index].forward().then((_) { setState(() { _timerItems.removeAt(index); _animationControllers.removeAt(index); }); }); } // 切换计时器运行状态 void _toggleTimer(int index) { setState(() { _timerItems[index].isRunning = !_timerItems[index].isRunning; if (_timerItems[index].isRunning) { _startTimer(index); } else { _timers[index]?.cancel(); _timers.remove(index); } }); } @override void dispose() { // 清理所有计时器与动画控制器 _timers.values.forEach((timer) => timer.cancel()); _animationControllers.forEach((controller) => controller.dispose()); super.dispose(); }
3. 列表项动画与UI布局
使用SlideTransition实现倒计时结束后的滑出动画,配合基础组件构建列表项UI:
// 构建单个列表项 Widget _buildTimerItem(int index) { final item = _timerItems[index]; final slideAnimation = Tween<Offset>( begin: Offset.zero, end: const Offset(1, 0), // 向右滑出屏幕 ).animate(CurvedAnimation( parent: _animationControllers[index], curve: Curves.easeInOut, )); return SlideTransition( position: slideAnimation, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), margin: const EdgeInsets.only(bottom: 8), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), boxShadow: const [BoxShadow(color: Colors.black12, blurRadius: 4)], ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(item.title, style: const TextStyle(fontSize: 16)), Row( children: [ Text( "${item.remainingSeconds ~/ 60}:${(item.remainingSeconds % 60).toString().padLeft(2, '0')}", style: TextStyle( fontSize: 16, color: item.remainingSeconds <= 10 ? Colors.redAccent : Colors.black87, ), ), const SizedBox(width: 8), IconButton( icon: Icon(item.isRunning ? Icons.pause_rounded : Icons.play_arrow_rounded), onPressed: () => _toggleTimer(index), ), ], ), ], ), ), ); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("计时器动画列表")), body: Padding( padding: const EdgeInsets.all(16), child: ListView.builder( itemCount: _timerItems.length, itemBuilder: (context, index) => _buildTimerItem(index), ), ), ); } }
关键优化点
- 生命周期管理:页面销毁时必须取消所有计时器、销毁动画控制器,防止内存泄漏。
- 性能优化:若列表项数量较多,推荐使用
AutomaticKeepAliveClientMixin保持列表项状态,或引入Provider/Bloc等状态管理工具统一管理计时器状态,简化State类逻辑。 - 动画扩展:可根据需求替换动画效果,比如使用
FadeTransition实现渐隐,或ScaleTransition实现缩放消失。
内容的提问来源于stack exchange,提问作者aak
相关产品推荐
相关产品推荐

