【问题标题】:How to create a parent listview that handles selecting items etc.?如何创建处理选择项目等的父列表视图?
【发布时间】:2020-12-10 06:08:03
【问题描述】:

我正在尝试创建一个基本列表视图,它负责单击列表拼贴并选择项目。 然后它会为每个项目显示一个复选框,并跟踪已选择的项目数量。 我所有的列表都需要这个特性,所以把它放在某个基类中是有意义的。 但是我将如何使用颤振来做到这一点?

以下代码包含部分逻辑:

  Widget build(BuildContext context) {
return ListView.separated(
  padding: const EdgeInsets.all(8),
  separatorBuilder: (context, index) => Divider(
    color: Colors.grey,
  ),
  itemCount: widget.models.length,
  itemBuilder: (BuildContext context, int index) {
    return ListTile(onLongPress: () {
      selectMode = true;
      widget.models[index].selected = true;
      selectCount++;
      setState(() {});
    }, onTap: () {
      if (selectMode) {
        if (widget.models[index].selected) {
          widget.models[index].selected = false;
          selectCount--;
        } else {
          widget.models[index].selected = true;
          selectCount++;
        }
        if (selectCount == 0) {
          selectMode = false;
        }
        setState(() {});
        return;
      }
    });
  },
);

}

我不知道如何从这里继续。当把它全部放在一个特定的列表中时,这显然工作得很好。但是将它放在基类中并简单地继承这种行为会更有意义。 是否可以将此逻辑移动到基类中,并且仍然可以为其他列表定义不同的 ListTiles? 我读到你根本不应该在颤振中继承小部件,所以我真的不知道如何继续,但肯定有比必须将此逻辑复制/粘贴到每个新列表中更好的方法。

编辑: ListTile 显示基于 selectMode 的复选框:

ListTile(
        onLongPress: () {
        },
        leading: CircleAvatar(
          radius: 30,
          backgroundColor: Color.fromARGB(255, 33, 84, 158),
          child: Icon(Icons.location_on, color: Colors.white, size: 40),
        ),
        title: Text('Title $index'),
        subtitle: Text('${models[index]}'),
        trailing: Visibility(
            visible: selectMode,
            child: models[index].selected == true
                ? Icon(Icons.check_box, color: Color.fromARGB(255, 33, 84, 158))
                : Icon(Icons.check_box_outline_blank,
                    color: Color.fromARGB(255, 33, 84, 158))),
        onTap: () {
        });

这是另一件事,应该成为“基础”的一部分,否则您必须将其粘贴到您创建的每个列表视图中。因此,当我有一些自定义列表视图小部件时,它已经内置了一个 listTile 来处理单击和显示复选框,新的列表视图如何能够具有不同样式的 listTile,可能没有前导图标等?

我创建了一个小 DartPad 来展示它是如何工作的: https://dartpad.dev/98d3f9b01c5b048d90aad3467aa3954e

现在,您希望在您创建的每个列表中都具有相同的行为,而无需再次编写相同的代码并且仍然能够使用不同类型的 listTiles,甚至可以向 onTap 事件等添加操作。

【问题讨论】:

    标签: flutter listview inheritance dart


    【解决方案1】:

    我不确定我是否完全理解您想要实现的目标,但根据我的理解,您似乎正在尝试重用特定的小部件。

    为此,您只需创建一个新的 Stateful 小部件,其中仅包含 ListView 的代码。然后为了确保它是“动态的”(即它可以使用不同的对象/模型列表),您必须在其构造函数中创建一个参数。

    此外,如果您想从另一个小部件访问总数,则需要使用回调。

    class MyCustomSelectableListView extends StatefulWidget {
       // Variable for your list of models. Replace Object with your Type
      final List<Object> models;
    
      // Callback to get the value of selectCount from another widget.
      final Function(int) getSelectCount; 
    
      // Passing the variables through a constructor.
      const MyCustomSelectableListView({this.models, this.getSelectCount, Key key})
          : super(key: key);
    
      @override
      _MyCustomSelectableListView createState() => _MyCustomSelectableListView();
    }
    
    class _MyCustomSelectableListView extends State<MyCustomSelectableListView> {
    
      // Your variables
      bool selectMode = false;
      int selectCount = 0;
    
      @override
      Widget build(BuildContext context) {
        return ListView.separated(
          padding: const EdgeInsets.all(8),
          separatorBuilder: (context, index) => Divider(
            color: Colors.grey,
          ),
          itemCount: widget.models.length,
          itemBuilder: (BuildContext context, int index) {
            return ListTile(onLongPress: () {
              selectMode = true;
              widget.models[index].selected = true;
              selectCount++;
              setState(() {});
            }, onTap: () {
              if (selectMode) {
                if (widget.models[index].selected) {
                  widget.models[index].selected = false;
                  selectCount--;
    
                  // Using the callback
                  widget.getSelectCount(selectCount);
                } else {
                  widget.models[index].selected = true;
                  selectCount++;
                  
                  // Using the callback
                  widget.getSelectCount(selectCount);
                }
                if (selectCount == 0) {
                  selectMode = false;
                }
                setState(() {});
                return;
              }
            });
          },
        );
      }
    }
    
    

    重用这段代码:

    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        List<Object> myListOfModels = [Object(), Object()];
        return Scaffold(
            body: MyCustomSelectableListView(
                models: myListOfModels,
                getSelectCount: (count) {
                  print(count);
                }));
      }
    }
    
    

    【讨论】:

    • 我的目标是拥有一个基本列表视图,例如选择项目。因此,在那之后,每当我需要一个列表视图时,我就可以重用我的基本列表视图,并且选择将始终有效。但是由于点击和长按事件是 listTile 的一部分,我不知道现在如何在不同的列表中使用不同的 listTiles。在 Android 中,您只需扩展适配器并将这些事件重定向到您的列表活动,然后您将其扩展为新列表。但在颤振中这是不可能的。
    • 你试过上面的代码吗?我个人认为你把事情复杂化了。我的收获是您想重用功能,对吗?另外,您选择项目的代码现在是否有效?现在代码看起来很乱,并且有更好和更简单的方法来实现在列表中选择项目。如果您愿意,我很乐意为您提供帮助。
    • 我已经更新了这个问题,它工作得很好。如果您知道解决此问题的更简单方法,我很高兴。但我想我的应用程序越复杂,我最终不得不将代码移动到基类的次数就越多,到目前为止我真的不知道应该如何在 Flutter 中完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多