Flutter树状视图展示插件list_treeview的使用

发布于 1周前 作者 vueper 来自 Flutter

Flutter树状视图展示插件list_treeview的使用

简介

list_treeview是一个基于Flutter ListView实现的树状视图插件,具有高度可定制性、高效性能以及支持无限层级子节点的特点。它只管理数据的树结构,UI由用户自行设计。

主要特性

  • 高度可定制:仅管理数据的树结构,UI由开发者自定义。
  • 性能高效:得益于ListView的复用机制。
  • 支持无限层级的子节点和子节点数量。

Flutter 2.0支持

从版本 0.3.0 开始支持Flutter 2.0的空安全特性。

使用指南

安装步骤

1. 添加依赖

pubspec.yaml文件中添加对list_treeview的依赖:

dependencies:
  list_treeview: [version]

2. 获取包

执行以下命令安装依赖:

$ flutter pub get

3. 导入包

在需要使用的Dart文件中导入list_treeview

import 'package:list_treeview/list_treeview.dart';

示例代码

以下是一个完整的示例,展示了如何使用list_treeview创建一个简单的树状视图:

import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:list_treeview/list_treeview.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: ElevatedButton(
          child: Text('TreeView'),
          onPressed: () {
            Navigator.push(context, CupertinoPageRoute(builder: (_) => TreePage()));
          },
        ),
      ),
    );
  }
}

/// 数据绑定类
class TreeNodeData extends NodeData {
  TreeNodeData({this.label, this.color}) : super();

  final String? label;
  final Color? color;

  String? property1;
  String? property2;
  String? property3;
}

class TreePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _TreePageState();
}

class _TreePageState extends State<TreePage> with SingleTickerProviderStateMixin {
  TreeViewController? _controller;
  bool _isSuccess = false;
  List<Color> _colors = [];

  @override
  void initState() {
    super.initState();
    _controller = TreeViewController();
    getData();
  }

  void getData() async {
    await Future.delayed(Duration(seconds: 2));

    var colors1 = TreeNodeData(label: 'Colors1');
    var color11 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 0, 139, 69));
    var color12 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 0, 191, 255));
    var color13 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 255, 106, 106));
    var color14 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 160, 32, 240));
    colors1.addChild(color11);
    colors1.addChild(color12);
    colors1.addChild(color13);
    colors1.addChild(color14);

    var colors2 = TreeNodeData(label: 'Colors2');
    var color21 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 255, 64, 64));
    var color22 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 28, 134, 238));
    var color23 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 255, 106, 106));
    var color24 = TreeNodeData(label: 'rgb(0,139,69)', color: Color.fromARGB(255, 205, 198, 115));
    colors2.addChild(color21);
    colors2.addChild(color22);
    colors2.addChild(color23);
    colors2.addChild(color24);

    _controller!.treeData([colors1, colors2]);

    setState(() {
      _isSuccess = true;
    });
  }

  Color getColor(int level) {
    return _colors[level % _colors.length];
  }

  Color randomColor() {
    int r = Random.secure().nextInt(200);
    int g = Random.secure().nextInt(200);
    int b = Random.secure().nextInt(200);
    return Color.fromARGB(255, r, g, b);
  }

  void add(TreeNodeData dataNode) {
    int r = Random.secure().nextInt(255);
    int g = Random.secure().nextInt(255);
    int b = Random.secure().nextInt(255);

    var newNode = TreeNodeData(label: 'rgb($r,$g,$b)', color: Color.fromARGB(255, r, g, b));
    _controller!.insertAtFront(dataNode, newNode);
  }

  void delete(dynamic item) {
    _controller!.removeItem(item);
  }

  void select(dynamic item) {
    _controller!.selectItem(item);
  }

  void selectAllChild(dynamic item) {
    _controller!.selectAllChild(item);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('TreeView')),
      body: _isSuccess ? getBody() : getProgressView(),
    );
  }

  Widget getProgressView() {
    return Center(child: CircularProgressIndicator());
  }

  Widget getBody() {
    return ListTreeView(
      shrinkWrap: false,
      padding: EdgeInsets.all(0),
      itemBuilder: (BuildContext context, NodeData data) {
        TreeNodeData item = data as TreeNodeData;
        double offsetX = item.level * 16.0;
        return Container(
          height: 54,
          padding: EdgeInsets.symmetric(horizontal: 16),
          decoration: BoxDecoration(border: Border(bottom: BorderSide(width: 1, color: Colors.grey))),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              Expanded(
                child: Padding(
                  padding: EdgeInsets.only(left: offsetX),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Padding(
                        padding: EdgeInsets.only(right: 5),
                        child: InkWell(
                          splashColor: Colors.amberAccent.withOpacity(1),
                          highlightColor: Colors.red,
                          onTap: () {
                            selectAllChild(item);
                          },
                          child: data.isSelected
                              ? Icon(Icons.star, size: 30, color: Color(0xFFFF7F50))
                              : Icon(Icons.star_border, size: 30, color: Color(0xFFFFDAB9)),
                        ),
                      ),
                      Text('level-${item.level}-${item.indexInParent}',
                          style: TextStyle(fontSize: 15, color: getColor(item.level))),
                    ],
                  ),
                ),
              ),
              Visibility(
                visible: item.isExpand,
                child: InkWell(
                  onTap: () {
                    add(item);
                  },
                  child: Icon(Icons.add, size: 30),
                ),
              )
            ],
          ),
        );
      },
      onTap: (NodeData data) {
        print('index = ${data.index}');
      },
      onLongPress: (data) {
        delete(data);
      },
      controller: _controller,
    );
  }
}

功能说明

  1. 初始化控制器

    • 在创建TreeView时必须初始化控制器。
    _controller = TreeViewController();
    
  2. 设置每行的数据

    • 数据类必须继承自NodeData,可以自定义其他属性。
    class TreeNodeData extends NodeData {
      TreeNodeData({this.label, this.color}) : super();
    
      final String? label;
      final Color? color;
    }
    
  3. 插入节点

    _controller.insertAtFront(dataNode, newNode);
    // 或者使用 insertAtRear 和 insertAtIndex 方法
    
  4. 删除节点

    _controller.removeItem(item);
    
  5. 展开或折叠子节点

    _controller.expandOrCollapse(index);
    
  6. 选择节点

    • 仅选中自身:
    _controller.selectItem(item);
    
    • 选中自身及其所有子节点:
    _controller.selectAllChild(item);
    

通过上述步骤,您可以轻松地在Flutter应用中集成并使用list_treeview插件来展示树状视图。


更多关于Flutter树状视图展示插件list_treeview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter树状视图展示插件list_treeview的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用list_treeview插件来展示树状视图的代码案例。首先,确保你已经在pubspec.yaml文件中添加了list_treeview依赖项:

dependencies:
  flutter:
    sdk: flutter
  list_treeview: ^最新版本号  # 请替换为最新版本号

然后,运行flutter pub get来获取依赖项。

以下是一个完整的示例代码,展示如何使用list_treeview插件来展示一个简单的树状视图:

import 'package:flutter/material.dart';
import 'package:list_treeview/list_treeview.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter TreeView Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  // 定义树状结构的数据
  final List<TreeViewNode> treeData = [
    TreeViewNode(
      title: 'Node 1',
      children: [
        TreeViewNode(
          title: 'Child 1.1',
        ),
        TreeViewNode(
          title: 'Child 1.2',
          children: [
            TreeViewNode(
              title: 'Grandchild 1.2.1',
            ),
          ],
        ),
      ],
    ),
    TreeViewNode(
      title: 'Node 2',
      children: [
        TreeViewNode(
          title: 'Child 2.1',
        ),
      ],
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter TreeView Example'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: TreeView(
          nodes: treeData,
          onNodeTap: (node) {
            // 当节点被点击时,执行的操作
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Tapped: ${node.title}'),
              ),
            );
          },
        ),
      ),
    );
  }
}

在这个示例中:

  1. 我们首先定义了一个包含树状结构数据的List<TreeViewNode>。每个TreeViewNode可以包含子节点,形成一个递归的树状结构。
  2. MyHomePagebuild方法中,我们使用TreeView小部件来展示这个树状结构。
  3. onNodeTap回调函数用于处理节点点击事件,这里简单地显示一个SnackBar,显示被点击节点的标题。

这个示例展示了如何使用list_treeview插件来展示和交互一个基本的树状视图。你可以根据实际需求,进一步自定义节点样式、增加功能等。

回到顶部