如何在 Flutter 中删除列表视图顶部的项目?

Posted

技术标签:

【中文标题】如何在 Flutter 中删除列表视图顶部的项目?【英文标题】:How to remove item at the top of List View in Flutter? 【发布时间】:2021-07-07 13:07:22 【问题描述】:

我有列表视图,并且在列表中的每个项目中都有一个名为“删除项目”的按钮。当我在每个项目中按下该按钮时,我只想从列表中删除该项目。

但它不会删除项目,它只是显示我指定的 Toast 消息。

我该如何解决这个问题?

这是代码:

Widget build(BuildContext context) 
listItems = buildVCsFromAPI(context);

return Container(
  child: ListView.builder(
      itemBuilder: (context, index) =>
          _buildListItem(context, listItems[index], index),
      itemCount: listItems.length,
      physics: AlwaysScrollableScrollPhysics()),
);


Widget _buildListItem(
  BuildContext context, _VerifiableCredentialListItem cert, int index) 
return GestureDetector(
  child: AnimatedAlign(
    curve: Curves.ease,
    duration: Duration(milliseconds: 500),
    heightFactor: selectedPosition == index ? factorMax : factorMin,
    alignment: Alignment.topCenter,
    child: Container(
      decoration: BoxDecoration(
          borderRadius: BorderRadius.all(Radius.circular(10)), //here
          color: Colors.white,
          boxShadow: [
            BoxShadow(
                color: Colors.grey.withOpacity(0.5),
                offset: Offset(0, -1),
                blurRadius: 10.0)
          ]),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          HeadingRow(title: cert.fullTitle, appIcon: cert.appIcon),
          displayListItem(index, selectedPosition, cert)
        ],
      ),
    ),
  ),
  

  Column displayListItem(
  int index, int selectedIndex, _VerifiableCredentialListItem cert) 
CredentialListGroupType groupType = cert.groupType;
return Column(
  crossAxisAlignment: CrossAxisAlignment.center,
  children: [
    SizedBox(
      height: UIConstants.s2,
    ),
    buildAnotherWidget(),
    SizedBox(
      height: UIConstants.s3,
    ),
    buildDeleteAndExportButtons(),
  ],
);


Column buildDeleteAndExportButtons() 
return Column(
  children: [
    Padding(
      padding: EdgeInsets.symmetric(
          vertical: UIConstants.s1, horizontal: UIConstants.s2),
      child: Row(
        children: [
          Expanded(
            flex: 1,
            child: BlueButtonWithIcon(
              text: 'Delete item',
              icon: 'assets/icons/delete-icon.svg',
              onPressed: () 
                setState(() 
                  AppToaster.pop(ToasterType.info, "Delete");
                  listItems.removeAt(0);
                );
              ,
            ),
          ),
          SizedBox(width: UIConstants.s1),
          Expanded(
            flex: 1,
            child: BlueButtonWithIcon(
              text: 'Export',
              icon: 'assets/icons/export.svg',
              onPressed: null,
            ),
          )
        ],
      ),
    ),
    SizedBox(height: UIConstants.s1)
  ],
);

【问题讨论】:

你在哪里声明了listItems 我已经编辑了代码。可以看看吗? 【参考方案1】:

调用 setState 并不意味着颤振实际上会完全重绘屏幕,这意味着它将检查您的小部件树与最后渲染的小部件树,它只会绘制差异,它首先比较小部件类型,然后是小部件键发现当前小部件和前一个小部件之间存在差异,因此,当您从项目列表中删除一个项目时,颤动会检查您返回的小部件到当前呈现的小部件,它没有发现任何差异,也不会重新绘制屏幕并继续显示最后一次渲染

因此,为了让您告诉颤振 listView 中的一个项目已更改,您可以为每个列表项小部件分配一个 uniqueKey 键,请注意,对于这个主题,您的键对于该小部件的数据应该是唯一的,否则您将面临性能问题,因为如果您的小部件键被更改而该小部件的表示在下次调用该构建方法时没有任何变化,这可能经常发生颤振将小部件键与呈现到屏幕并存在于上的前一个小部件键进行比较渲染树,它发现键不同,它会重新绘制该小部件,这是一个冗余操作,因为您的小部件 UI 和表示是相同的

例如,根据数据的索引或内容为 listItems 中的每个数据模型分配一个唯一 id,并使用它为该数据表示的小部件创建 ValueKey()

这是一个列表的工作示例,当您单击列表项时,第一个列表项将被删除

class ListItemDataModel 
  final String id;
  final Color color;

  ListItemDataModel(this.id, this.color);


class _MyHomePageState extends State<MyHomePage> 
  List<ListItemDataModel> items = [];

  @override
  void initState() 
    super.initState();
    items = [
      ListItemDataModel("A", Colors.red),
      ListItemDataModel("B", Colors.amber),
      ListItemDataModel("C", Colors.green),
      ListItemDataModel("D", Colors.lightBlueAccent),
      ListItemDataModel("E", Colors.pink),
    ];
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        child: ListView.builder(
          itemBuilder: (context, index) 
            return GestureDetector(
              key: ValueKey(items[index].id),
              //Tap to Remove first item from list
              onTap: () 
                items.removeAt(0);
                setState(() );
              ,
              child: Container(
                height: 60,
                color: items[index].color,
                child: Center(
                  child: Text(
                      "This is a unique item with id = $items[index].id"),
                ),
              ),
            );
          ,
          itemCount: items.length,
        ),
      ),
    );
  

【讨论】:

我试过用钥匙,但我无法让它工作。我应该向哪个小部件添加 Key? 到第一级小部件,我会用一个例子来更新我的答案【参考方案2】:

所以,

我们无法访问上面的代码.. 所以.. listItems 是从哪里来的? 也许您在初始化状态后检索 listItems 的值?如果是这样,您总是检索到相同的结果是正常的..

你应该做的是:

从参数、全局变量、数据库 ecc 中获取 listItems 值 显示列表 当您删除单个项目时,您应该更新原始列表 现在状态已更新,列表将加载更新后的值

如果您从列表中删除了一个项目,但该列表随后以原始形式重新加载,您的更新将丢失

【讨论】:

感谢您的评论。我更新了代码以显示我在哪里获取 listItems。它来自 API 调用,我做了一些映射来过滤值。

以上是关于如何在 Flutter 中删除列表视图顶部的项目?的主要内容,如果未能解决你的问题,请参考以下文章

如何在列表视图顶部添加一行

在颤动中向上/向下滚动列表时如何在列表中插入和删除项目?

Flutter - 删除ListView中项目之间的空间

Flutter Provider-重建列表项而不是列表视图

Flutter:如何在列表视图中通过拖放对项目进行排序?

Flutter:如何知道列表视图中的项目位置?