flutter - 我的 Flutter ListView 总是从列表中删除最后一项

标签 flutter dart listview

我正在创建一个 Flutter Widget,当我尝试从我正在使用的列表中删除一个项目时,它总是删除最后一个项目,我认为这可能是一个 Key 问题,但没有什么适合它,有谁知道我该如何解决这个问题?

代码

create_game.dart

import 'package:flutter/material.dart';
import 'package:pontinho/components/custom_input.dart';

class CreateGame extends StatefulWidget {
  const CreateGame({super.key});

  @override
  State<CreateGame> createState() => _CreateGameState();
}

class _CreateGameState extends State<CreateGame> {
  List<String> names = [''];

  void changeName(int nameIndex, String change) {
    setState(() {
      names[nameIndex] = change;
    });
  }

  void removeName(int nameIndex) {
    print(names);
    print(nameIndex);
    setState(() {
      names.removeAt(nameIndex);
    });
  }

  ListView createNamesInput() {
    return ListView.builder(
      itemCount: names.length,
      shrinkWrap: true,
      itemBuilder: (context, index) {
        return ListTile(
          key: ObjectKey(index),
          title: CustomInput(
            key: ObjectKey(index),
            labelText: "Nome",
            onChanged: (String changed) => changeName(index, changed),
            text: names[index],
            onRemoved: () => removeName(index),
          ),
        );
      },
    );
    // return names
    //     .asMap()
    //     .entries
    //     .map((el) => CustomInput(
    //           key: ObjectKey('${el.key}'),
    //           labelText: "Nome",
    //           onChanged: changeName,
    //           index: el.key,
    //           text: names[el.key],
    //           onRemoved: removeName,
    //         ))
    //     .toList();
  }

  void addName() {
    setState(() {
      names.add('');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: GestureDetector(
          onTap: (() => Navigator.pop(context)),
          child: const Icon(
            Icons.arrow_back,
            color: Colors.black,
            size: 40,
          ),
        ),
        backgroundColor: Colors.white,
        titleTextStyle: const TextStyle(
          color: Colors.black,
          fontSize: 20,
        ),
        title: const Text("CRIE SEU JOGO"),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(
          vertical: 8,
          horizontal: 16,
        ),
        // child: createNamesInput(),
        child: Column(
          children: [
            createNamesInput(),
            Padding(
              padding: const EdgeInsets.symmetric(vertical: 10),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  TextButton(
                    onPressed: addName,
                    child: Row(
                      children: const [
                        Icon(Icons.add),
                        Text('Adicionar Jogador'),
                      ],
                    ),
                  ),
                ],
              ),
            ),
            SizedBox(
              width: double.infinity,
              height: 50,
              child: ElevatedButton(
                onPressed: () => print('Iniciar!'),
                child: const Text('Iniciar!'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

自定义输入.dart

import 'package:flutter/material.dart';

typedef OneArgumentCallback = void Function(String changed);

class CustomInput extends StatefulWidget {
  final OneArgumentCallback onChanged;
  final VoidCallback onRemoved;
  final String labelText;
  final String text;

  const CustomInput({
    super.key,
    required this.onChanged,
    required this.labelText,
    required this.text,
    required this.onRemoved,
  });

  @override
  State<CustomInput> createState() => _CustomInputState();
}

class _CustomInputState extends State<CustomInput> {
  late final TextEditingController inputController;

  @override
  void initState() {
    super.initState();
    inputController = TextEditingController(text: widget.text);
  }

  void changeContent(String value) {
    widget.onChanged(
      value,
    );
  }

  @override
  Widget build(BuildContext context) {
    return TextFormField(
      key: widget.key,
      controller: inputController,
      textDirection: TextDirection.ltr,
      decoration: InputDecoration(
        border: const UnderlineInputBorder(),
        labelText: widget.labelText,
        suffixIcon: IconButton(
          onPressed: () => widget.onRemoved(),
          icon: const Icon(
            Icons.close,
            color: Colors.red,
          ),
        ),
      ),
      autocorrect: false,
      onChanged: (value) => changeContent(value),
    );
  }
}

最佳答案

确实这是一个key问题,您必须创建一个组合键,该组合键对于每个项目必须是唯一的,我将indexnames[index合并],

CustomInput(
  key: ObjectKey('$index:${names[index]}'),
  labelText: "Nome",
  onChanged: (String changed) => changeName(index, changed),
  text: names[index],
  onRemoved: () => removeName(index),
),

请注意,如果您单独尝试此代码,文本字段将失去焦点,因为键已更改,这可以通过删除 onChange 内的 setState 来解决

void changeName(int nameIndex, String change) {
  names[nameIndex] = change;
}

此处您不需要 setState,因为当您在文本字段中输入内容时,UI 将默认更新

我希望我说清楚了

关于flutter - 我的 Flutter ListView 总是从列表中删除最后一项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75000198/

相关文章:

HTTP 连接问题

dart - Angular Dart中的分层路径参数

android - 查看寻呼机和 ListView

listview - 从ListView获取ClickedItem(使用MVVM)

google-maps - 谷歌地图 flutter 检查多边形内的点

android - 在 flutter 中仅显示图像的顶部部分

gradle - Flutter 应用程序卡在 "Running Gradle task ' assembleDebug'...”

dart - 如何在 Dart 中获取脚本路径?

ios - 有没有办法在 flutter 中从 iOS 中排除一个包?

android - 如何从包含可点击项目的 ListView 中获取该行的行 ID?