You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 22:54:55