首页 > 解决方案 > Flutter:从列表中删除元素不会删除循环生成的相应UI元素

问题描述

我有一个 DataTable,我在其中将带有 for 循环的 DataRows 添加到 UI。循环遍历列表。在 UI 上,可以在列表中添加和删除项目。

如图所示,每个 DataRow 都有 TextFormFields 以获取一些输入。这是我的问题:当我在行的 TextFields 中放入一些值然后删除其中一个行时,尽管我更改了 List 中的值并相应地更新了状态,但最后一行总是被删除。

带有 TextFormFields 的 DataTableRows

因此,例如,如果我尝试删除图片中权重设置为 10 的第一行,则在最后一行消失后,第一行中的值 10 仍然存在。由于我在删除行时更新了状态,并且输入都将它们的 initialValues 设置为与列表中的值相对应,所以 10 的行不应该消失吗?还是我的思维过程有问题?打印语句显示正确的 ListItem 被删除,所以我不太确定这里发生了什么。

我对 Flutter 和 Dart 真的很陌生,所以非常感谢任何帮助!

这里是表的代码:

import "package:flutter/material.dart";
import 'package:pr_note_app/definitions/ExerciseSet.dart';

class ExerciseTable extends StatefulWidget {
  final String name;

  ExerciseTable({Key key, @required this.name}) : super(key: key);

  @override
  _ExerciseTableState createState() => _ExerciseTableState();
}

class _ExerciseTableState extends State<ExerciseTable> {
  var _sets = [new ExerciseSet("-", "", "")];

  void popUpMenuButtonItemSelected(value) {
    switch (value) {
      case "Add Set":
        setState(() {
          _sets.add(new ExerciseSet("-", "", ""));
        });
        break;
      default:
    }
  }

  void removeSetAt(index) {
    print(_sets);
    setState(() {
      _sets.removeAt(index);
    });
    print(_sets);
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        AppBar(
          elevation: 0,
          title: TextFormField(
            initialValue: widget.name,
            cursorColor: Colors.black,
            decoration: new InputDecoration(
                border: InputBorder.none,
                focusedBorder: InputBorder.none,
                enabledBorder: InputBorder.none,
                errorBorder: InputBorder.none,
                disabledBorder: InputBorder.none,
                hintText: "My New Exercise"),
          ),
          actions: [
            PopupMenuButton(
              itemBuilder: (BuildContext context) => <PopupMenuEntry>[
                const PopupMenuItem(value: "Add Set", child: Text("Add Set")),
                const PopupMenuItem(
                    value: "Remove Exercise", child: Text("Remove Exercise"))
              ],
              onSelected: (value) => popUpMenuButtonItemSelected(value),
            ),
          ],
          iconTheme: IconThemeData(color: Colors.black),
          automaticallyImplyLeading: false,
          backgroundColor: Colors.white,
        ),
        // SET NUMBER | LAST | WEIGHT | REPS
        DataTable(
          showCheckboxColumn: false,
          columnSpacing: 30,
          columns: const <DataColumn>[
            DataColumn(
              label: Text(
                'Set',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
            ),
            DataColumn(
              label: Text(
                'Last',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
            ),
            DataColumn(
              label: Text(
                'Weight',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
            ),
            DataColumn(
              label: Text(
                'Reps',
                style: TextStyle(fontStyle: FontStyle.italic),
              ),
            ),
            DataColumn(label: Text(""))
          ],
          rows: [
            for (var i = 0; i < _sets.length; i++)
              DataRow(onSelectChanged: (bool) => print("select $bool"), cells: [
                // SET NUMBER
                DataCell(Text("${i + 1}")),
                // LAST
                DataCell(Text("${_sets[i].last}")),
                // WEIGHT
                DataCell(Container(
                    width: MediaQuery.of(context).size.width * 0.13,
                    child: TextFormField(
                        initialValue: "${_sets[i].weight}",
                        onChanged: (value) {
                          setState(() {
                            _sets[i].weight = value;
                          });
                        },
                        cursorColor: Colors.black,
                        decoration: new InputDecoration(
                          isDense: true,
                          fillColor: Colors.grey[200],
                          filled: true,
                          border: InputBorder.none,
                          focusedBorder: InputBorder.none,
                          enabledBorder: InputBorder.none,
                          errorBorder: InputBorder.none,
                          disabledBorder: InputBorder.none,
                        )))),
                // REPS
                DataCell(Container(
                    width: MediaQuery.of(context).size.width * 0.13,
                    child: TextFormField(
                        initialValue: "${_sets[i].reps}",
                        onChanged: (value) {
                          setState(() {
                            _sets[i].reps = value;
                          });
                        },
                        cursorColor: Colors.black,
                        decoration: new InputDecoration(
                          isDense: true,
                          fillColor: Colors.grey[200],
                          filled: true,
                          border: InputBorder.none,
                          focusedBorder: InputBorder.none,
                          enabledBorder: InputBorder.none,
                          errorBorder: InputBorder.none,
                          disabledBorder: InputBorder.none,
                        )))),
                DataCell(Container(
                  width: MediaQuery.of(context).size.width * 0.13,
                  child: IconButton(
                    icon: Icon(Icons.delete),
                    onPressed: () => removeSetAt(i),
                    color: Colors.black,
                  ),
                ))
              ])
          ],
        )
      ],
      crossAxisAlignment: CrossAxisAlignment.stretch,
    );
  }
}

标签: flutterdart

解决方案


原因可能是框架无法确定分配给项目的状态。您需要将密钥添加到DataRow

DataKey(
key: ObjectKey(_sets[i]),
...

推荐阅读