Flutter分组展开折叠插件grouped_expansion_tile的使用

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

Flutter分组展开折叠插件grouped_expansion_tile的使用

特性

这个小部件用于展示带有展开折叠功能的分组数据。

简单用法

设置 databuilder 属性。data 必须是一个扩展了 GroupBase 类的对象。如果你不需要额外的属性,可以直接使用 GroupBase 类。builder 会分配给展开折叠小部件的标题属性。

class Category extends GroupBase {
  String additional;
  Category({
    required this.additional,
    required String uid,
    String? parent,
  }) : super(uid: uid, parent: parent);
}

List<Category> _createList() {
  final topParents = List.generate(10,
      (index) => Category(additional: "auto-generated-$index", uid: "2$index"));

  return [
    Category(additional: "group-1", uid: "1"),
    Category(additional: "group-2", uid: "2"),
    Category(additional: "group-1-1", uid: "3", parent: "1"),
    Category(additional: "group-2-1", uid: "4", parent: "2"),
    Category(additional: "group-3", uid: "5"),
    Category(additional: "group-2-1-1", uid: "6", parent: "4"),
    Category(additional: "group-2-2", uid: "7", parent: "2"),
    Category(additional: "group-2-3", uid: "8", parent: "2"),
    Category(additional: "group-2-1-1-1", uid: "9", parent: "6"),
    Category(additional: "group-2-1-1-2", uid: "10", parent: "6"),
    ...topParents,
  ];
}

final groupedExpansionTile = GroupedExpansionTile<Category>(
  data: _createList(),
  builder: (parent, depth) => Text(parent.self.additional),
);

return Scaffold(
  appBar: AppBar(
    title: const Text("Simplest"),
  ),
  body: groupedExpansionTile,
);

启用拖拽手势

你可以使每个项目都可以被拖动。将 draggable 属性设为 true 以启用拖拽。你可以指定自己的边框来高亮目标小部件,当它接受拖动项时。当目标项接受拖动项时,onAccept 会被调用。你可以在那里编写自己的处理逻辑,例如更新项目列表。

final List<Category> _data = _createList();
GroupedExpansionTile<Category>(
  data: _data,
  builder: (parent, depth) => Text(parent.self.additional),
  childIndent: 50,
  controlAffinity: ListTileControlAffinity.trailing,
  initialBorder: Border.all(color: Colors.orange, width: 1),
  highlightedBorder:
      Border.all(color: Colors.deepPurple.shade800, width: 3),
  initiallyExpanded: false,
  draggable: true,
  onAccept: (source, dest) async {
    setState(() {
      // source 是 _data 中的一个元素
      source.self.parent = dest?.uid;
    });
  },
  onExpansionChanged: (expanded, parent, depth) {
    setState(() {
      parent.self.additional += "@";
    });
  },
  padding: EdgeInsets.zero,
);

已知问题

  • 当拖动第三级项目时,顶级项目会接受被拖动的项目,只要拖动位置在小部件内。它应该只在被拖动的位置在已折叠的父区域时接受被拖动的项目。

完整示例Demo

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

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // 这个小部件是你的应用的根
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const GroupedExtensionTileSample(),
    );
  }
}

class Category extends GroupBase {
  String additional;
  Category({
    required this.additional,
    required String uid,
    String? parent,
  }) : super(uid: uid, parent: parent);
}

List<Category> _createList() {
  final topParents = List.generate(10,
      (index) => Category(additional: "auto-generated-$index", uid: "2$index"));

  return [
    Category(additional: "group-1", uid: "1"),
    Category(additional: "group-2", uid: "2"),
    Category(additional: "group-1-1", uid: "3", parent: "1"),
    Category(additional: "group-2-1", uid: "4", parent: "2"),
    Category(additional: "group-3", uid: "5"),
    Category(additional: "group-2-1-1", uid: "6", parent: "4"),
    Category(additional: "group-2-2", uid: "7", parent: "2"),
    Category(additional: "group-2-3", uid: "8", parent: "2"),
    Category(additional: "group-2-1-1-1", uid: "9", parent: "6"),
    Category(additional: "group-2-1-1-2", uid: "10", parent: "6"),
    ...topParents,
  ];
}

Future<void> _showDialog(
  BuildContext context,
  String title,
  String text,
) async {
  final alert = AlertDialog(
    title: Text(title),
    content: Text(text),
    actions: [
      TextButton(
        onPressed: () {
          Navigator.of(context).pop();
        },
        child: const Text("OK"),
      ),
    ],
  );
  await showDialog(
    context: context,
    builder: (BuildContext context) => alert,
  );
}

class GroupedExtensionTileSample extends StatelessWidget {
  const GroupedExtensionTileSample({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: const Text("Grouped Extension Sample"),
        ),
        body: PageView(
          children: [
            _createSimplestSample(),
            const GroupedExtensionTileSample2(),
          ],
        ),
      ),
    );
  }

  Widget _createSimplestSample() {
    final groupedExpansionTile = GroupedExpansionTile<Category>(
      data: _createList(),
      builder: (parent, depth) => Text(parent.self.additional),
    );

    return Scaffold(
      appBar: AppBar(
        title: const Text("Simplest"),
      ),
      body: groupedExpansionTile,
    );
  }
}

class GroupedExtensionTileSample2 extends StatefulWidget {
  const GroupedExtensionTileSample2({Key? key}) : super(key: key);

  [@override](/user/override)
  _GroupedExtensionTileSample2 createState() => _GroupedExtensionTileSample2();
}

class _GroupedExtensionTileSample2 extends State<GroupedExtensionTileSample2> {
  final List<Category> _data = _createList();

  [@override](/user/override)
  Widget build(BuildContext context) {
    final groupedExpansionTile = GroupedExpansionTile<Category>(
      data: _data,
      builder: (parent, depth) => Text(parent.self.additional),
      childIndent: 50,
      controlAffinity: ListTileControlAffinity.trailing,
      initialBorder: Border.all(color: Colors.orange, width: 1),
      highlightedBorder:
          Border.all(color: Colors.deepPurple.shade800, width: 3),
      initiallyExpanded: false,
      draggable: true,
      onAccept: (source, dest) async {
        setState(() {
          // source 是 _data 中的一个元素
          source.self.parent = dest?.uid;
        });
      },
      onExpansionChanged: (expanded, parent, depth) {
        setState(() {
          parent.self.additional += "@";
        });
      },
      padding: EdgeInsets.zero,
    );

    return Scaffold(
      appBar: AppBar(
        title: const Text("Advanced"),
      ),
      body: groupedExpansionTile,
    );
  }
}

更多关于Flutter分组展开折叠插件grouped_expansion_tile的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter分组展开折叠插件grouped_expansion_tile的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter中使用grouped_expansion_tile插件来实现分组展开和折叠功能的代码示例。grouped_expansion_tile是一个第三方包,用于在Flutter应用中创建分组可折叠的列表项。

首先,确保你已经在pubspec.yaml文件中添加了grouped_expansion_tile依赖:

dependencies:
  flutter:
    sdk: flutter
  grouped_expansion_tile: ^latest_version  # 请替换为实际的最新版本号

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

以下是一个完整的示例代码,展示如何使用grouped_expansion_tile

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  final List<String> groupTitles = ['Group 1', 'Group 2', 'Group 3'];
  final Map<String, List<String>> groupItems = {
    'Group 1': ['Item 1.1', 'Item 1.2', 'Item 1.3'],
    'Group 2': ['Item 2.1', 'Item 2.2'],
    'Group 3': ['Item 3.1', 'Item 3.2', 'Item 3.3', 'Item 3.4'],
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Grouped Expansion Tile Demo'),
      ),
      body: ListView.separated(
        itemCount: groupTitles.length,
        separatorBuilder: (_, __) => Divider(),
        itemBuilder: (_, index) {
          final String groupTitle = groupTitles[index];
          final List<String> items = groupItems[groupTitle]!;

          return GroupedExpansionTile(
            title: Text(groupTitle),
            children: List.generate(
              items.length,
              (subIndex) {
                return ListTile(
                  title: Text(items[subIndex]),
                );
              },
            ),
          );
        },
      ),
    );
  }
}

代码解释

  1. 依赖导入:首先导入grouped_expansion_tile包。
  2. 主应用:创建一个MyApp类作为应用入口,它包含一个MaterialApp
  3. 主页MyHomePage是一个有状态的Widget,它持有分组标题和分组项的数据。
  4. 数据准备:定义了两个列表,groupTitles存储分组标题,groupItems是一个映射,存储每个分组下的子项。
  5. 构建UI:在build方法中,使用ListView.separated来创建一个列表视图,每个列表项是一个GroupedExpansionTile
  6. GroupedExpansionTile:每个GroupedExpansionTile的标题由groupTitles提供,子项由groupItems提供,并生成相应的ListTile

运行这段代码,你将看到一个包含多个可折叠分组的列表,每个分组标题点击后可以展开或折叠其下的子项。

希望这个示例对你有帮助!如果你有任何其他问题,请随时提问。

回到顶部