当onPressed按钮时如何从ListView中删除TextField?

时间:2019-05-30 21:47:21

标签: flutter dart

当用户单击“清除图标”按钮时如何删除TextField? (不仅清除TextField的文本)

用户故事
用户单击按钮以添加播放器。 (从技术角度讲,此按钮添加了TextField)
用户可以在文本字段上输入播放器的名称。
用户单击“清除图标”按钮以删除当前的TextField(与add函数相反)。

enter image description here

new ListView.builder(
                     padding: EdgeInsets.all(0),
                      shrinkWrap: true,
                      physics: NeverScrollableScrollPhysics(),
                      itemCount: 5,
                      itemBuilder: (context, index) {
                        print(index);
                        return TextField(
                          maxLength: 20,
                          decoration: InputDecoration(
                            labelText: "Player ${index+1}",
                            counterText: "",
                            prefixIcon: const Icon(Icons.person),
                            suffixIcon: new IconButton(
                                icon: Icon(Icons.clear),
                                onPressed: () =>
                                  setState(() {
                                    this.dispose(); // -----Doesn't work----
                                  })
                                ),
                          ),
                        );
                      }
                    ),

例如,如果用户单击“清除按钮”,则在播放器4上设置“约翰”,然后删除播放器4的TextField。它将仅保留4个TextField

enter image description here

2 个答案:

答案 0 :(得分:2)

我假设的事实:

  1. 您希望能够从(到)列表中删除(或添加)字段
  2. 您希望在删除字段时保留其余字段的值
  3. 列表可以大于5

解决方案:

如果您希望以上所有内容均成立,那么实际上您需要跟踪TextFields的TextEditingController,而不是文本字段本身。这是因为TextField的值实际上存储在TextEditingController中(如果不为每个小部件提供该值,则会即时创建)。检查一下:

import 'package:flutter/material.dart';

// needs to be StatefulWidget, so we can keep track of the count of the fields internally
class PlayerList extends StatefulWidget {
  const PlayerList({
    this.initialCount = 5,
  });

  // also allow for a dynamic number of starting players
  final int initialCount;

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

class _PlayerListState extends State<PlayerList> {
  int fieldCount = 0;
  int nextIndex = 0;
  // you must keep track of the TextEditingControllers if you want the values to persist correctly
  List<TextEditingController> controllers = <TextEditingController>[];

  // create the list of TextFields, based off the list of TextControllers
  List<Widget> _buildList() {
    int i;
    // fill in keys if the list is not long enough (in case we added one)
    if (controllers.length < fieldCount) {
      for (i = controllers.length; i < fieldCount; i++) {
        controllers.add(TextEditingController());
      }
    }

    i = 0;
    // cycle through the controllers, and recreate each, one per available controller
    return controllers.map<Widget>((TextEditingController controller) {
      int displayNumber = i + 1;
      i++;
      return TextField(
        controller: controller,
        maxLength: 20,
        decoration: InputDecoration(
          labelText: "Player $displayNumber",
          counterText: "",
          prefixIcon: const Icon(Icons.person),
          suffixIcon: IconButton(
            icon: Icon(Icons.clear),
            onPressed: () {
              // when removing a TextField, you must do two things:
              // 1. decrement the number of controllers you should have (fieldCount)
              // 2. actually remove this field's controller from the list of controllers
              setState(() {
                fieldCount--;
                controllers.remove(controller);
              });
            },
          ),
        ),
      );
    }).toList(); // convert to a list
  }


  @override
  Widget build(BuildContext context) {
    // generate the list of TextFields
    final List<Widget> children = _buildList();

    // append an 'add player' button to the end of the list
    children.add(
      GestureDetector(
        onTap: () {
          // when adding a player, we only need to inc the fieldCount, because the _buildList()
          // will handle the creation of the new TextEditingController
          setState(() {
            fieldCount++;
          });
        },
        child: Container(
          color: Colors.blue,
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Text(
              'add player',
              style: TextStyle(
                color: Colors.white,
              ),
            ),
          ),
        ),
      ),
    );

    // build the ListView
    return ListView(
      padding: EdgeInsets.all(0),
      shrinkWrap: true,
      physics: NeverScrollableScrollPhysics(),
      children: children,
    );
  }

  @override
  void initState() {
    super.initState();

    // upon creation, copy the starting count to the current count
    fieldCount = widget.initialCount;
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  void didUpdateWidget(PlayerList oldWidget) {
    super.didUpdateWidget(oldWidget);
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
  }
}

有了上述内容,您可以:

  • 启动应用
  • 将玩家2更改为“ bob”
  • 将玩家3更改为“史蒂夫”
  • 将玩家4更改为“查尔斯”
  • 删除播放器3
  • 观察到玩家2是'bob',新玩家3是'charles'

我认为这就是您在这里寻找的东西。

答案 1 :(得分:-1)

您可以拥有一个属性来检查用户是否单击了该按钮,并取决于您显示/隐藏TextField的值。在下面,如果用户单击X按钮,则仅使用一个布尔属性,然后将hideField设置为true,TextField将被大小为零的小部件替换。

 new ListView.builder(
                    padding: EdgeInsets.all(0),
                    shrinkWrap: true,
                    physics: NeverScrollableScrollPhysics(),
                    itemCount: 5,
                    itemBuilder: (context, index) {
                      print(index);
                      bool hideField = false; // I added it here

                      return hideField ? SizedBox.shrink() : TextField(
                        maxLength: 20,
                        decoration: InputDecoration(
                          labelText: "Player ${index + 1}",
                          counterText: "",
                          prefixIcon: const Icon(Icons.person),
                          suffixIcon: new IconButton(
                              icon: Icon(Icons.clear),
                              onPressed: () =>
                                  setState(() {
                                    hideField = true; // Now it works
                                  })
                          ),
                        ),
                      );
                    }
                )