如何让ListView中每个ListTile的ValueNotifier与进度条单独绑定?
解决ListView中进度条与输入框单独绑定的问题
你当前的问题核心是所有ListTile共用了同一个全局的ValueNotifier,不管哪个输入框提交数值,都会更新这个唯一的ValueNotifier,导致所有进度条同步变化。要实现一对一绑定,必须让每个列表项拥有独立的状态管理。
解决方案
把单个玩家的列表项抽成独立的StatefulWidget,每个实例维护自己的ValueNotifier,这样输入框和对应的进度条就能形成专属绑定。
修改后的完整代码
首先是拆分出的单个玩家列表项组件:
import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:flutter/material.dart'; import 'package:simple_circular_progress_bar/simple_circular_progress_bar.dart'; class SinglePlayerTile extends StatefulWidget { final QueryDocumentSnapshot<Map<String, dynamic>> document; const SinglePlayerTile({Key? key, required this.document}) : super(key: key); @override State<SinglePlayerTile> createState() => _SinglePlayerTileState(); } class _SinglePlayerTileState extends State<SinglePlayerTile> { late ValueNotifier<double> _valueNotifier; @override void initState() { super.initState(); // 每个列表项初始化独立的ValueNotifier _valueNotifier = ValueNotifier(0.0); } @override void dispose() { // 页面销毁时释放资源,避免内存泄漏 _valueNotifier.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return ListTile( leading: SimpleCircularProgressBar( size: 50, progressStrokeWidth: 8, backStrokeWidth: 8, // 使用当前列表项专属的ValueNotifier valueNotifier: _valueNotifier, mergeMode: true, onGetText: (double value) { return Text( '${value.toInt()}', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.normal, color: Colors.white, ), ); }, ), title: Text( widget.document["gn"], textAlign: TextAlign.center, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), contentPadding: const EdgeInsets.all(10), subtitle: TextField( textAlign: TextAlign.center, keyboardType: TextInputType.number, keyboardAppearance: Brightness.dark, decoration: InputDecoration( filled: true, fillColor: const Color.fromARGB(255, 190, 183, 183).withOpacity(0.4), hintText: 'Enter value (max 100)', hintStyle: TextStyle(color: Colors.black.withOpacity(0.9)), ), style: const TextStyle(fontSize: 25, color: Colors.white), onSubmitted: (inputText) { // 增加输入合法性校验,避免非法数值异常 final double? newValue = double.tryParse(inputText); if (newValue != null && newValue >= 0 && newValue <= 100) { _valueNotifier.value = newValue; } }, ), trailing: const Icon(Icons.more_vert), ); } }
然后修改原有的PlayerTile组件:
class PlayerTile extends StatelessWidget { const PlayerTile({Key? key, required this.documents}) : super(key: key); final List<QueryDocumentSnapshot<Map<String, dynamic>>> documents; @override Widget build(BuildContext context) { return ListView( children: <Widget>[ for (final document in documents) ...[ SinglePlayerTile(document: document), const Divider(height: 0), ], ], ); } }
关键改动说明
- 拆分
SinglePlayerTile后,每个列表项拥有独立的_valueNotifier,彻底实现输入框与进度条的一对一绑定。 - 在
dispose方法中释放ValueNotifier,避免长期持有内存导致泄漏。 - 增加输入合法性校验,处理非数字输入、超出0-100范围的情况,提升稳定性。
- 原
PlayerTile改为StatelessWidget,因为它不再需要维护全局状态,仅负责遍历生成子组件。
内容的提问来源于stack exchange,提问作者Saito Shirogane
相关产品推荐
相关产品推荐

