Flutter树形视图展示插件flutter_treeview_plus的使用

Flutter树形视图展示插件flutter_treeview_plus的使用

flutter_treeview_plus 是一个用于在 Flutter 应用中展示树形数据的插件。它可以帮助开发者以层级结构的形式展示数据,如组织架构图、文件目录等。

example

示例代码

以下是 flutter_treeview_plus 插件的一个完整示例代码。

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_treeview_plus/flutter_treeview_plus.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Treeview Plus',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Flutter Treeview Plus'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  [@override](/user/override)
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final treeData = <TreeNodeData>[];
  final selectedOrganizationChart = <ItemOrganizationChart>{};

  [@override](/user/override)
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback((_) async {
      final strOrganizationChart =
          await rootBundle.loadString('assets/organization_chart.json');
      final organizationChartJson = json.decode(strOrganizationChart);
      final organizationChart = OrganizationChart(
        data: (organizationChartJson['data'] as List<dynamic>?)?.map((e) {
          return ItemOrganizationChart.fromJson(e);
        }).toList(),
      );
      final data = organizationChart.data ?? [];
      treeData.addAll(
        List.generate(
          data.length,
          (index) => mapOrganizationChartToTreeNodeData(data[index], null),
        ),
      );
      setState(() {});
    });
    super.initState();
  }

  TreeNodeData mapOrganizationChartToTreeNodeData(
      ItemOrganizationChart itemOrganizationChart, TreeNodeData? parent) {
    final children = itemOrganizationChart.children ?? [];
    final treeNodeData = TreeNodeData(
      title: itemOrganizationChart.name ?? '-',
      expanded: itemOrganizationChart.isExpanded,
      checked: itemOrganizationChart.isChecked,
      children: [],
      parent: parent,
      extra: itemOrganizationChart,
    );
    final nestedChildren = children.isEmpty
        ? <TreeNodeData>[]
        : children
            .map((e) => mapOrganizationChartToTreeNodeData(e, treeNodeData))
            .toList();
    treeNodeData.children = nestedChildren;
    return treeNodeData;
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: treeData.isEmpty
          ? const Center(
              child: CircularProgressIndicator.adaptive(),
            )
          : FlutterTreeviewPlus(
              data: treeData,
              showCheckBox: true,
              manageParentState: true,
              onChange: (List<TreeNodeData> listTreeNode) {
                selectedOrganizationChart.clear();
                for (final treeNode in listTreeNode) {
                  handleOnChange(treeNode);
                }
                /*final listSelectedNames = selectedOrganizationChart.map((e) => e.name ?? '-');
                debugPrint('list selected names: $listSelectedNames');*/
              },
            ),
    );
  }

  void handleOnChange(TreeNodeData treeNode) {
    final isChecked = treeNode.checked;
    final data = treeNode.extra as ItemOrganizationChart;
    if (isChecked == null) {
      // Check the children
      final children = treeNode.children;
      if (children.isNotEmpty) {
        for (final child in children) {
          handleOnChange(child);
        }
      }
    } else if (isChecked) {
      // Added to list selected
      selectedOrganizationChart.add(data);
    }
  }
}

class OrganizationChart {
  final List<ItemOrganizationChart>? data;

  OrganizationChart({required this.data});

  [@override](/user/override)
  String toString() {
    return 'OrganizationChart{data: $data}';
  }
}

class ItemOrganizationChart {
  final int? id;
  final int? pid;
  final String? name;
  final List<ItemOrganizationChart>? children;
  bool isChecked;
  bool isExpanded;

  ItemOrganizationChart({
    required this.id,
    required this.pid,
    required this.name,
    required this.children,
    this.isChecked = false,
    this.isExpanded = false,
  });

  factory ItemOrganizationChart.fromJson(Map<String, dynamic> json) {
    return ItemOrganizationChart(
      id: json['id'],
      pid: json['pid'],
      name: json['name'],
      children: (json['children'] as List<dynamic>?)?
          .map(
              (e) => ItemOrganizationChart.fromJson(e as Map<String, dynamic>))
          .toList(),
    );
  }

  [@override](/user/override)
  String toString() {
    return 'ItemOrganizationChart{id: $id, pid: $pid, name: $name, children: $children, isChecked: $isChecked, '
        'isExpanded: $isExpanded}';
  }
}

代码解释

  1. 导入必要的库

    import 'dart:convert';
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:flutter_treeview_plus/flutter_treeview_plus.dart';
    
  2. 定义主应用类

    void main() {
      runApp(const MyApp());
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      [@override](/user/override)
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Treeview Plus',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: const MyHomePage(title: 'Flutter Treeview Plus'),
        );
      }
    }
    
  3. 定义主页状态类

    class MyHomePage extends StatefulWidget {
      const MyHomePage({super.key, required this.title});
    
      final String title;
    
      [@override](/user/override)
      State<MyHomePage> createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      final treeData = <TreeNodeData>[];
      final selectedOrganizationChart = <ItemOrganizationChart>{};
    
      [@override](/user/override)
      void initState() {
        WidgetsBinding.instance.addPostFrameCallback((_) async {
          final strOrganizationChart =
              await rootBundle.loadString('assets/organization_chart.json');
          final organizationChartJson = json.decode(strOrganizationChart);
          final organizationChart = OrganizationChart(
            data: (organizationChartJson['data'] as List<dynamic>?)?.map((e) {
              return ItemOrganizationChart.fromJson(e);
            }).toList(),
          );
          final data = organizationChart.data ?? [];
          treeData.addAll(
            List.generate(
              data.length,
              (index) => mapOrganizationChartToTreeNodeData(data[index], null),
            ),
          );
          setState(() {});
        });
        super.initState();
      }
    
  4. 将数据转换为树节点数据

    TreeNodeData mapOrganizationChartToTreeNodeData(
        ItemOrganizationChart itemOrganizationChart, TreeNodeData? parent) {
      final children = itemOrganizationChart.children ?? [];
      final treeNodeData = TreeNodeData(
        title: itemOrganizationChart.name ?? '-',
        expanded: itemOrganizationChart.isExpanded,
        checked: itemOrganizationChart.isChecked,
        children: [],
        parent: parent,
        extra: itemOrganizationChart,
      );
      final nestedChildren = children.isEmpty
          ? <TreeNodeData>[]
          : children
              .map((e) => mapOrganizationChartToTreeNodeData(e, treeNodeData))
              .toList();
      treeNodeData.children = nestedChildren;
      return treeNodeData;
    }
    
  5. 构建页面

    [@override](/user/override)
    Widget build(BuildContext context) {
      return Scaffold(
        appBar: AppBar(
          title: Text(widget.title),
        ),
        body: treeData.isEmpty
            ? const Center(
                child: CircularProgressIndicator.adaptive(),
              )
            : FlutterTreeviewPlus(
                data: treeData,
                showCheckBox: true,
                manageParentState: true,
                onChange: (List<TreeNodeData> listTreeNode) {
                  selectedOrganizationChart.clear();
                  for (final treeNode in listTreeNode) {
                    handleOnChange(treeNode);
                  }
                },
              ),
      );
    }
    
  6. 处理选中状态变化

    void handleOnChange(TreeNodeData treeNode) {
      final isChecked = treeNode.checked;
      final data = treeNode.extra as ItemOrganizationChart;
      if (isChecked == null) {
        // Check the children
        final children = treeNode.children;
        if (children.isNotEmpty) {
          for (final child in children) {
            handleOnChange(child);
          }
        }
      } else if (isChecked) {
        // Added to list selected
        selectedOrganizationChart.add(data);
      }
    }
    
  7. 定义组织架构数据模型

    class OrganizationChart {
      final List<ItemOrganizationChart>? data;
    
      OrganizationChart({required this.data});
    
      [@override](/user/override)
      String toString() {
        return 'OrganizationChart{data: $data}';
      }
    }
    
    class ItemOrganizationChart {
      final int? id;
      final int? pid;
      final String? name;
      final List<ItemOrganizationChart>? children;
      bool isChecked;
      bool isExpanded;
    
      ItemOrganizationChart({
        required this.id,
        required this.pid,
        required this.name,
        required this.children,
        this.isChecked = false,
        this.isExpanded = false,
      });
    
      factory ItemOrganizationChart.fromJson(Map<String, dynamic> json) {
        return ItemOrganizationChart(
          id: json['id'],
          pid: json['pid'],
          name: json['name'],
          children: (json['children'] as List<dynamic>?)?
              .map(
                  (e) => ItemOrganizationChart.fromJson(e as Map<String, dynamic>))
              .toList(),
        );
      }
    
      [@override](/user/override)
      String toString() {
        return 'ItemOrganizationChart{id: $id, pid: $pid, name: $name, children: $children, isChecked: $isChecked, '
            'isExpanded: $isExpanded}';
      }
    }
    

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

1 回复

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


flutter_treeview_plus 是一个用于在 Flutter 应用中展示树形结构的插件。它可以帮助你轻松地创建和管理树形视图,支持展开、折叠节点,以及自定义节点的样式和行为。下面是如何使用 flutter_treeview_plus 插件的详细步骤。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 flutter_treeview_plus 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  flutter_treeview_plus: ^1.0.0  # 请检查最新版本

然后运行 flutter pub get 来安装依赖。

2. 基本用法

以下是一个简单的例子,展示如何使用 flutter_treeview_plus 来创建一个树形视图。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('TreeView Example'),
        ),
        body: TreeViewExample(),
      ),
    );
  }
}

class TreeViewExample extends StatefulWidget {
  @override
  _TreeViewExampleState createState() => _TreeViewExampleState();
}

class _TreeViewExampleState extends State<TreeViewExample> {
  TreeViewController? _treeViewController;
  final List<Node> _nodes = [
    Node(
      key: '1',
      label: 'Node 1',
      children: [
        Node(
          key: '1.1',
          label: 'Node 1.1',
        ),
        Node(
          key: '1.2',
          label: 'Node 1.2',
          children: [
            Node(
              key: '1.2.1',
              label: 'Node 1.2.1',
            ),
            Node(
              key: '1.2.2',
              label: 'Node 1.2.2',
            ),
          ],
        ),
      ],
    ),
    Node(
      key: '2',
      label: 'Node 2',
    ),
  ];

  @override
  void initState() {
    super.initState();
    _treeViewController = TreeViewController(
      children: _nodes,
    );
  }

  @override
  Widget build(BuildContext context) {
    return TreeView(
      controller: _treeViewController!,
      onExpansionChanged: (key, expanded) {
        setState(() {
          _treeViewController!.expandNode(key, expanded);
        });
      },
      onNodeTap: (key) {
        print('Node $key tapped');
      },
    );
  }
}

3. 主要组件和属性

  • TreeViewController: 用于控制树形视图的状态,包括节点的展开和折叠。
  • Node: 表示树形视图中的一个节点,可以包含子节点。
  • TreeView: 用于展示树形视图的组件。

4. 自定义节点样式

你可以通过 TreeViewnodeBuilder 属性来自定义节点的样式。例如:

TreeView(
  controller: _treeViewController!,
  onExpansionChanged: (key, expanded) {
    setState(() {
      _treeViewController!.expandNode(key, expanded);
    });
  },
  onNodeTap: (key) {
    print('Node $key tapped');
  },
  nodeBuilder: (BuildContext context, Node node) {
    return Container(
      padding: EdgeInsets.all(8.0),
      child: Row(
        children: [
          Icon(Icons.folder),
          SizedBox(width: 8.0),
          Text(node.label),
        ],
      ),
    );
  },
);

5. 动态更新树形结构

你可以通过 TreeViewController 动态地添加、删除或更新节点。例如:

void _addNode() {
  setState(() {
    _treeViewController!.addNode(
      Node(
        key: '3',
        label: 'Node 3',
      ),
      parentKey: '1', // Optional: add as a child of Node 1
    );
  });
}

6. 处理节点事件

你可以通过 onNodeTaponExpansionChanged 来处理节点的点击和展开/折叠事件。

TreeView(
  controller: _treeViewController!,
  onExpansionChanged: (key, expanded) {
    setState(() {
      _treeViewController!.expandNode(key, expanded);
    });
  },
  onNodeTap: (key) {
    print('Node $key tapped');
  },
);
回到顶部