【问题标题】:Flutter Sortable Drag And Drop ListViewFlutter 可排序拖放 ListView
【发布时间】:2019-05-23 07:08:55
【问题描述】:

所以我开始学习 Flutter,并想使用材料设计拖放列表,就像在材料指南网站上看到的那样。

https://storage.googleapis.com/spec-host-backup/mio-design%2Fassets%2F1dtprsH4jZ2nOnjBCJeJXd7n4U-jmWyas%2F03-list-reorder.mp4

与此相比,到目前为止我尝试过的所有库看起来都像垃圾一样。是否有一个我缺少的好库或原生 Flutter 小部件?

【问题讨论】:

    标签: listview drag-and-drop flutter flutter-animation


    【解决方案1】:

    你可以使用原生的flutter widget,ReorderableListView来实现,这里是实现的例子。

    List<String> _list = ["Apple", "Ball", "Cat", "Dog", "Elephant"];
    
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(),
        body: ReorderableListView(
          children: _list.map((item) => ListTile(key: Key("${item}"), title: Text("${item}"), trailing: Icon(Icons.menu),)).toList(),
          onReorder: (int start, int current) {
            // dragging from top to bottom
            if (start < current) {
              int end = current - 1;
              String startItem = _list[start];
              int i = 0;
              int local = start;
              do {
                _list[local] = _list[++local];
                i++;
              } while (i < end - start);
              _list[end] = startItem;
            }
            // dragging from bottom to top
            else if (start > current) {
              String startItem = _list[start];
              for (int i = start; i > current; i--) {
                _list[i] = _list[i - 1];
              }
              _list[current] = startItem;
            }
            setState(() {});
          },
        ),
      );
    }
    

    【讨论】:

    • 长按重​​新排序
    • 只是一个细节,据我了解,您应该避免空的 setState 调用,在我看来,onReorder 中的所有代码也可以在 setState 调用中?
    • 请注意,长按重新排序绝对违反了材料设计规范,不应在 Android 上使用(不知道 iOS)。据我所知,目前还没有办法提供可以简单地用ReorderableListView 抓取的句柄
    • @DavidMulder 这就是 Flutter 的实现方式,你可以在 Github 上提交一个 bug 提到这个问题。
    • @A.Bourgoin 不正确,请检查material.io/components/lists#behavior“要重新排序列表项,请拖动它。”。 “长按”是针对内容块描述的,而不是列表(例如,正常拖动意味着选择的编辑器)或具有清晰拖动句柄的元素。
    【解决方案2】:

    Flutter 本身提供了一个(Material)ReorderableListView class

    【讨论】:

    • 看来我做了一些无用的工作))) 总之,这是一次有趣的经历。遗憾的是 `ReorderableListView' 没有使用 builder,但我想我会用它来满足我的需要。谢谢
    • @AndreyTurkovsky ReorderableListView 也有 builder api.flutter.dev/flutter/material/ReorderableListView/…
    【解决方案3】:

    我已经尝试过flutter_reorderable_listdragable_flutter_list,但它们都不能正常工作——在拖动过程中出现了一些不需要的伪影。 所以我尝试了自己的解决方案:

    ListView.builder(
      itemBuilder: (context, index) => buildRow(index),
      itemCount: trackList.length,
    ),
    
    Widget buildRow(int index) {
      final track = trackList[index];
      ListTile tile = ListTile(
        title: Text('${track.getName()}'),
      );
      Draggable draggable = LongPressDraggable<Track>(
        data: track,
        axis: Axis.vertical,
        maxSimultaneousDrags: 1,
        child: tile,
        childWhenDragging: Opacity(
          opacity: 0.5,
          child: tile,
        ),
        feedback: Material(
          child: ConstrainedBox(
            constraints:
                BoxConstraints(maxWidth: MediaQuery.of(context).size.width),
            child: tile,
          ),
          elevation: 4.0,
        ),
      );
    
      return DragTarget<Track>(
        onWillAccept: (track) {
          return trackList.indexOf(track) != index;
        },
        onAccept: (track) {
          setState(() {
            int currentIndex = trackList.indexOf(track);
            trackList.remove(track);
            trackList.insert(currentIndex > index ? index : index - 1, track);
          });
        },
        builder: (BuildContext context, List<Track> candidateData,
            List<dynamic> rejectedData) {
          return Column(
            children: <Widget>[
              AnimatedSize(
                duration: Duration(milliseconds: 100),
                vsync: this,
                child: candidateData.isEmpty
                    ? Container()
                    : Opacity(
                        opacity: 0.0,
                        child: tile,
                      ),
              ),
              Card(
                child: candidateData.isEmpty ? draggable : tile,
              )
            ],
          );
        },
      );
    }
    

    我想,这不是最好的解决方案,我可能会进一步改变它,但现在它工作得很好

    【解决方案4】:

    检查knopp/flutter_reorderable_list。它实现了这一点。 它真的很流畅,没有性能问题,能够处理数千个项目。

    但是,它的实现并不像通常的颤振小部件那样容易。

    如果您对此感到困惑,我建议您使用我创建的小部件将flutter/ReorderableListViews 移植到knopp/ReorderableList

    这个小部件使它非常易于使用,但它没有提供相同的灵活性,并且由于它与 children List 一起使用,它不像原来那样可扩展。

    这是code for ReorderableListSimple,这是the demo

    【讨论】:

    • 您的版本运行良好,谢谢。我希望它在重新排序每个图块时不那么滞后。不知道发行版会不会更流畅。另外,我不知道如何在重新排序时自定义/删除振动。
    • 我还遇到了一个问题,当我将列表磁贴设为可关闭 (flutter.io/docs/cookbook/gestures/dismissible) 时,手柄不会移动,而其余部分会滑开。
    • 我知道这不是一个解决方案,但在我的应用程序中,经过一番斗争,我决定使用重新排序模式。 :( 所以在重新排序模式下,我使用 ReorderingList 并且有一个句柄(你不能做任何其他事情),当它不重新排序时,用户可以做所有其余的事情。
    • 如果您使用ReorderingListSimple,也许您可​​以使用childrenAlreadyHaveListener = true,然后手动将ReorderableListener 放入ListTile 并使其在Dismissible``s onRezize 上消失!让我知道它是否有效!我知道这不是很好,但也许它是有效的临时解决方案。
    【解决方案5】:

    Flutter 团队介绍了ReorderableListView 小部件。

    ReorderableListView(
          children: <Widget>[
            for (var item in appState.menuButtons) 
            Text('data')              
    
          ],
        )
    

    【讨论】:

    • 请注意,这目前缺少一些在 ListView 中实现的功能。 Flutter 团队知道,但他们仍然愿意接受建议。你可以在这里关注:github.com/flutter/flutter/issues/66080
    猜你喜欢
    • 2014-07-05
    • 1970-01-01
    • 2012-07-08
    • 2018-08-28
    • 1970-01-01
    • 1970-01-01
    • 2013-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多