[译]Flutter 强大灵活的树形组件 flutter_fancy_tree_view

Flutter 强大灵活的树形组件 flutter_fancy_tree_view

原文链接:flutter_fancy_tree_view | Flutter Package (flutter-io.cn)

译时版本:1.4.1


flutter_fancy_tree_view

Flutter 组件和 sliver(滑动内容)的集合,可用于将层级数据可视化。

该库使用了回调集以深度优先顺序来遍历层级数据,将所需信息收集到 Dart 的List(树的扁平展示)中, 然后使用 sliver 在屏幕上渲染树的节点。

截图

空白缩进
连接线
范围标线

安装

运行以下命令:

csharp 复制代码
flutter pub add flutter_fancy_tree_view

它会向包的 pubspec.yaml 中添加如下的代码行(会自动运行 flutter pub get):

yaml 复制代码
dependencies:
  flutter_fancy_tree_view: any

现在在 Dart 代码中,可如下使用:

arduino 复制代码
import 'package:flutter_fancy_tree_view/flutter_fancy_tree_view.dart';

⚠️ 警告

请将版本 '1.0' 作为一个全新的包来看待。不鼓励从旧版本升级,因为该包大部分已经重写,并有很多破坏性改动。

特性

  • 动态 "树节点" 模型
  • 可使用任何组件
  • 缩进向导
  • 展开/折叠动画
  • sliver 树变体
  • 支持基本的拖拽

要体验这些特性,可访问 live 示例应用。 示例应用的源代码可在 example目录中找到。

开始

前往 example/example.md查看一下该包基本用法的示例,示例的注释很完善。 也可以在 example/lib/src/examples 查看一些特定特性的示例。

用法

  1. 创建一个 "树节点" 模型来存储数据
kotlin 复制代码
class MyTreeNode {
  const MyTreeNode({
    required this.title,
    this.children = const <MyTreeNode>[],
  });

  final String title;
  final List<MyTreeNode> children;
}
  1. 创建/获取层级数据
csharp 复制代码
final List<MyTreeNode> roots = [
  const MyTreeNode(title: 'My static root node'),
  ...fetchOtherRootNodes(),
];
  1. 初始化树控制器 TreeController
ini 复制代码
final treeController = TreeController<MyTreeNode>(
  roots: roots,
  childrenProvider: (MyTreeNode node) => node.children,
);

注意: 如查打算使用拖拽特性,确保在 TreeController 中包含 parentProvider 。一些方法如 expandAncestorscheckNodeHasAncestor 依赖 parentProvider 运转。不设置时会在调试模式抛出断言错误。

  1. 将控制器传给树视图 TreeView ,然后提供一个组件构建器将数据映射为组件。确保包含树节点展开状态的方式和缩进组件TreeIndentation以适当地缩进它们。
less 复制代码
@override
Widget build(BuildContext context) {
  return AnimatedTreeView<MyTreeNode>(
    treeController: treeController,
    nodeBuilder: (BuildContext context, TreeEntry<MyTreeNode> entry) {
      return InkWell(
        onTap: () => treeController.toggleExpansion(entry.node),
        child: TreeIndentation(
          entry: entry,
          child: Text(entry.node.title),
        ),
      );
    },
  );
}

拖拽

对于可用示例,可前往 example/lib/src/examples 目录下的拖拽示例代码。

该包提供了两个新的组件 TreeDraggableTreeDragTarget ,它们封装了 Flutter 的 DraggableDragTarget 组件,添加了一些树视图需要的处理,如悬停时自动展开/折叠的节点、在可滚动的视口组件垂直边缘附近拖拽时自动滚动,等。

现在修改一下前面的例子来包含拖拽特性。

首先,修改"树节点"模型来包含父节点的引用,这是一个重要的步骤,它能确保展开/折叠行为能正常动作。

kotlin 复制代码
class MyTreeNode {
  MyTreeNode({
    required this.title,
    Iterable<MyTreeNode>? children,
  }) : children = <MyTreeNode>[] {
    if (children == null) return;

    for (final MyTreeNode child in children) {
      this.children.add(child);

      // 确保更新目标节点的子组件时能更新它的父节点。
      child.parent = this;
    }
  }

  final String title;
  final List<MyTreeNode> children;
  MyTreeNode? parent;
}

修改了树节点模型后,现在确保 TreeController 包含 parentProvider 回调以访问目标树节点的祖先。 对于拖拽特性非常重要,对于方法如 expandAncestors 也很重要。如果 parentProvider 没有定义,则会使用总是返回 null (例,(MyTreeNode node) => null)的回调,并且需要它的方法会在调试模式下会抛出断言错误。

ini 复制代码
final treeController = TreeController<MyTreeNode>(
  ...,
  parentProvider: (MyTreeNode node) => node.parent,
);

现在,修改树节点组件以包含 TreeDraggableTreeDragTarget 组件。

less 复制代码
@override
Widget build(BuildContext context) {
  return AnimatedTreeView<MyTreeNode>(
    treeController: treeController,
    nodeBuilder: (BuildContext context, TreeEntry<MyTreeNode> entry) {
      return TreeDragTarget<MyTreeNode>(
        node: entry.node,
        onNodeAccepted: (TreeDragAndDropDetails details) {
          // 可选,确保目标节点已展开,所以在树重新构建时被拖拽的节点在其附近是可见的。
          treeController.setExpansionState(details.targetNode, true);

          // TODO: 实现树的重排序逻辑

          // 确保重新构建树视图以在新的附近表示重排序后的节点。
          treeController.rebuild();
        },
        builder: (BuildContext context, TreeDragAndDropDetails? details) {
          Widget myTreeNodeTile = Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(entry.node.title),
          );

          // 如果 details 不为空,拖拽的节点会悬停在拖拽目标上。可添加一些反馈给用户。
          if (details != null) {
            myTreeNodeTile = ColoredBox(
              color: Theme.of(context).colorScheme.primary.withOpacity(0.3),
              child: myTreeNodeTile,
            );
          }

          return TreeDraggable<MyTreeNode>(
            node: entry.node,

            // 在拖拽的指针下面向用户表示一些反馈,这可以是任意组件。
            feedback: IntrinsicWidth(
              child: Material(
                elevation: 4,
                child: myTreeNodeTile,
              ),
            ),

            child: InkWell(
              onTap: () => treeController.toggleExpansion(entry.node),
              child: TreeIndentation(
                entry: entry,
                child: myTreeNodeTile,
              ),
            ),
          );
        },
      );
    },
  );
}

API 文档

前往 pub.dev api 文档


相关推荐
火柴就是我2 小时前
flutter 之真手势冲突处理
android·flutter
Speed1233 小时前
`mockito` 的核心“打桩”规则
flutter·dart
法的空间3 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
恋猫de小郭3 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
玲珑Felone4 小时前
从flutter源码看其渲染机制
android·flutter
ALLIN1 天前
Flutter 三种方式实现页面切换后保持原页面状态
flutter
Dabei1 天前
Flutter 国际化
flutter
Dabei1 天前
Flutter MQTT 通信文档
flutter
Dabei1 天前
Flutter 中实现 TCP 通信
flutter
孤鸿玉1 天前
ios flutter_echarts 不在当前屏幕 白屏修复
flutter