Flutter:使用单个主时钟同时更新多个倒计时Widget
不用复杂状态管理的解决方案
核心思路是把所有倒计时的结束时间数据统一放在父组件管理,用一个主Timer触发父组件的setState,子Widget只负责根据传入的结束时间计算剩余时长并渲染,不用自己维护Timer。
步骤如下:
- 父组件维护一个存储每个倒计时结束时间的列表(比如用
List<DateTime>) - 父组件创建单个
Timer.periodic,每秒调用setState,触发整个ListView重建 - 子Widget是无状态组件,接收结束时间作为参数,每次父组件重建时,自动计算当前剩余时间并更新UI
代码示例
父组件(包含ListView和主Timer)
class CountdownList extends StatefulWidget { const CountdownList({super.key}); @override State<CountdownList> createState() => _CountdownListState(); } class _CountdownListState extends State<CountdownList> { late Timer _timer; // 存储每个倒计时的结束时间,这里模拟3个不同的倒计时 final List<DateTime> _endTimes = [ DateTime.now().add(const Duration(seconds: 60)), DateTime.now().add(const Duration(seconds: 120)), DateTime.now().add(const Duration(seconds: 180)), ]; @override void initState() { super.initState(); // 启动主Timer,每秒触发一次更新 _timer = Timer.periodic( const Duration(seconds: 1), (timer) { setState(() { // 无需修改数据,setState会触发ListView重建,子Widget自动计算剩余时间 }); }, ); } @override void dispose() { _timer.cancel(); // 销毁Timer,避免内存泄漏 super.dispose(); } @override Widget build(BuildContext context) { return ListView.builder( itemCount: _endTimes.length, itemBuilder: (context, index) { return CountdownItem(endTime: _endTimes[index]); }, ); } }
子组件(单个倒计时Widget)
class CountdownItem extends StatelessWidget { final DateTime endTime; const CountdownItem({super.key, required this.endTime}); // 计算剩余时间的工具方法 String _getRemainingTime() { final now = DateTime.now(); final difference = endTime.difference(now); if (difference.isNegative) return "已结束"; return "${difference.inMinutes}:${(difference.inSeconds % 60).toString().padLeft(2, '0')}"; } @override Widget build(BuildContext context) { return ListTile( title: Text("倒计时:${_getRemainingTime()}"), ); } }
方案优势
- 所有Timer逻辑集中在父组件,避免多个Timer占用资源
- 子Widget仅负责展示,无需维护自身状态,代码更简洁
- Flutter的diff算法会自动识别需要更新的UI部分,不会有明显性能问题
如果需要动态添加/删除倒计时,只需修改父组件的_endTimes列表并调用setState,子Widget会自动同步更新。
内容的提问来源于stack exchange,提问作者Preem Palver2
相关产品推荐
相关产品推荐

