如何在flutter中添加另一个可重新排序的列表视图

问题描述 投票:0回答:1

我正在学习Flutter,是否有可能创建一个可重排序列表,其中包含的项目本身就是可重排序列表(下图)。如果有人可以建议我或帮助我,我将不胜感激。谢谢

这是我的代码

class _ReorderItemsState extends State<ReorderItems> {

  List<String> topTen = [
    "EPL",
    "MLS",
    "LLG",
  ];
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ReorderableListView(
        onReorder: onReorder,
        children: getListItem(),
      ),
    );
  }

  List<ExpansionTile> getListItem() => topTen.asMap()
  .map((index, item) => MapEntry(index, buildTenableListTile(item, index)))
  .values.toList();

  ExpansionTile buildTenableListTile(String item, int index) => ExpansionTile(
    key: ValueKey(item),
    title: Text(item),
    leading: Icon(Icons.list),
    backgroundColor: Colors.blue,
  );

  void onReorder(int oldIndex, int newIndex){
    if(newIndex > oldIndex){
      newIndex -=1;
    }
    setState(() {
      String game = topTen[oldIndex];
      topTen.removeAt(oldIndex);
      topTen.insert(newIndex, game);
    });
  }
}
flutter flutter-layout flutter-dependencies flutter-animation flutter-web
1个回答
0
投票

您可以通过设置children小部件的ExpansionTile属性来实现。

方法如下。

  1. 您需要一个通用的数据处理程序或某种状态管理,以将父级和子级的状态保持在小部件外部,以避免在子级列表更改时进行重建。为简便起见,我使用单例来保存公共数据。在实际情况下,这应该是基于ChangeNotifierBLoc的方法。但是,如果要更改父级或子级列表,则不需要,因为Flutter控件是不可变的,因此需要完全重建。
/// Holding the common data as a singleton to avoid excessive rebuilds.
/// Usually this should be replaced with a manager or bloc or changenotifier class
class DataHolder {
  List<String> parentKeys;

  Map<String, List<String>> childMap;

  DataHolder._privateConstructor();

  static final DataHolder _dataHolder = DataHolder._privateConstructor();

  static DataHolder get instance => _dataHolder;

  factory DataHolder.initialize({@required parentKeys}) {
    _dataHolder.parentKeys = parentKeys;
    _dataHolder.childMap = {};
    for (String key in parentKeys) {
      _dataHolder.childMap.putIfAbsent(
          key, () => ['${key}child_1', '${key}child_2', '${key}child_3']);
    }
    return _dataHolder;
  }
}
  1. [创建一个小部件,为每个小部件返回具有唯一ReorderableListView的子级ScrollController。例如ReorderList小部件。它几乎与您编写的内容相同,除了我返回ListTile而不是ExpansionTile并设置scrollController属性。当前的稳定版本不具有此属性。因此,在此解决方案中,它包装有PrimaryScrollController小部件,以避免重复使用scrollController。

class ReorderList extends StatefulWidget {
  final String parentMapKey;
  ReorderList({this.parentMapKey});
  @override
  _ReorderListState createState() => _ReorderListState();
}

class _ReorderListState extends State<ReorderList> {
  @override
  Widget build(BuildContext context) {
    return PrimaryScrollController(
      controller: ScrollController(),
      child: ReorderableListView(
        // scrollController: ScrollController(),
        onReorder: onReorder,
        children: DataHolder.instance.childMap[widget.parentMapKey]
            .map(
              (String child) => ListTile(
                key: ValueKey(child),
                leading: Icon(Icons.done_all),
                title: Text(child),
              ),
            )
            .toList(),
      ),
    );
  }

  void onReorder(int oldIndex, int newIndex) {
    if (newIndex > oldIndex) {
      newIndex -= 1;
    }
    List<String> children = DataHolder.instance.childMap[widget.parentMapKey];
    String game = children[oldIndex];
    children.removeAt(oldIndex);
    children.insert(newIndex, game);
    DataHolder.instance.childMap[widget.parentMapKey] = children;
    // Need to set state to rebuild the children.
    setState(() {});
  }
}


  1. 在父级ExpansionTile小部件中,将此新小部件设置为children之一。此子级和父级都是从DataHolder单例类的值构建的。

    注意,我设置了恒定的高度以避免布局冲突。您必须将其用于动态尺寸。

class ReorderItems extends StatefulWidget {
  final List<String> topTen;
  ReorderItems({this.topTen});
  @override
  _ReorderItemsState createState() => _ReorderItemsState();
}

class _ReorderItemsState extends State<ReorderItems> {
  @override
  void initState() {
    super.initState();
    // initialize the children for the Expansion tile
    // This initialization can be replaced with any logic like network fetch or something else.
    DataHolder.initialize(parentKeys: widget.topTen);
  }

  @override
  Widget build(BuildContext context) {
    return PrimaryScrollController(
      key: ValueKey(widget.topTen.toString()),
      controller: ScrollController(),
      child: ReorderableListView(
        onReorder: onReorder,
        children: getListItem(),
      ),
    );
  }

  List<ExpansionTile> getListItem() => DataHolder.instance.parentKeys
      .asMap()
      .map((index, item) => MapEntry(index, buildTenableListTile(item, index)))
      .values
      .toList();

  ExpansionTile buildTenableListTile(String mapKey, int index) => ExpansionTile(
        key: ValueKey(mapKey),
        title: Text(mapKey),
        leading: Icon(Icons.list),
        backgroundColor: Colors.blue,
        children: [
          Container(
            key: ValueKey('$mapKey$index'),
            height: 400,
            child: ReorderList(
              parentMapKey: mapKey,
            ),
          ),
        ],
      );

  void onReorder(int oldIndex, int newIndex) {
    if (newIndex > oldIndex) {
      newIndex -= 1;
    }
    setState(() {
      String game = DataHolder.instance.parentKeys[oldIndex];
      DataHolder.instance.parentKeys.removeAt(oldIndex);
      DataHolder.instance.parentKeys.insert(newIndex, game);
    });
  }
}

codepen中提供了一个完整的解决方案。我更改了代码以从父窗口小部件动态接受项目列表。您将必须尝试如何维护数据并减少重建。但是总的来说,只要保持列表,孩子ReorderableListView就可以工作。

希望这会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.