Flutter分组列表展示插件simple_grouped_listview的使用

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

Flutter分组列表展示插件simple_grouped_listview的使用

简介

simple_grouped_listview 是一个Flutter插件,用于在ListView中显示分组项目。通过这个插件,你可以轻松地将列表项按照某种规则进行分组,并且可以自定义分组头和列表项的样式。

使用场景

有时候你有一个 List<T> 并且希望以某种特定的方式显示它。例如,T 有一个 DateTime 字段,你想根据年、月、日或混合方式对它们进行分组。使用这个插件,你可以轻松实现这些需求。

主要特性

  1. Custom Grouped ListView:带有头部构建器和列表项构建器。
  2. List Grouped ListView:带有头部构建器和每个列表项的构建器。
  3. Grid Grouped ListView:带有头部构建器和每个网格项的构建器。
  4. Custom Grouped ListView with Custom Builder:为每个分组项(头部和列表项)提供构建器。

这些功能可以帮助你创建如下的效果:

Simple List Simple Grid Sticky List

安装

添加依赖

在你的 pubspec.yaml 文件中添加以下内容:

dependencies:
  simple_grouped_listview: "^1.0.0"

导入包

在你的Dart文件中导入包:

import 'package:simple_grouped_listview/simple_grouped_listview.dart';

使用方法

必要参数

  • items:你想要显示的 List<T>
  • itemGrouper:一个函数 H Function(T item)H 是用于分组的头部类型。例如,如果你想根据 DateTime 的年份来分组,那么 itemGrouper 可以是 itemGrouper: (T i) => T.dateTime.year

构造函数

有三种构造函数可用:

  • GroupedListView.list():将 List<T> 显示为 ListView
  • GroupedListView.grid():将 List<T> 显示为 GridView
  • GroupedListView():完全自定义显示方式。

示例代码

Simple

GroupedListView.list(
    items: List<int>.generate(100, (index) => index + 1),
    itemGrouper: (int i) => i.isEven,
    headerBuilder: (context, bool isEven) => Container(
        color: Colors.amber,
        child: Text(
            isEven ? 'Even' : 'Odd',
            style: const TextStyle(fontWeight: FontWeight.bold),
        ),
        padding: const EdgeInsets.all(16),
    ),
    listItemBuilder:
        (context, int countInGroup, int itemIndexInGroup, int item, int itemIndexInOriginalList) =>
            Container(
        child: Text(item.toRadixString(10), textAlign: TextAlign.center),
        padding: const EdgeInsets.all(8),
    ),
);

Grid

GroupedListView.grid(
    items: List<int>.generate(100, (index) => index + 1),
    itemGrouper: (int i) => i.isEven,
    headerBuilder: (context, bool isEven) => Container(
        color: Colors.amber,
        child: Text(
            isEven ? 'Even' : 'Odd',
            style: const TextStyle(fontWeight: FontWeight.bold),
        ),
        padding: const EdgeInsets.all(16),
    ),
    gridItemBuilder:
        (context, int countInGroup, int itemIndexInGroup, int item, int itemIndexInOriginalList) =>
            Container(
        child: Text(item.toRadixString(10), textAlign: TextAlign.center),
        padding: const EdgeInsets.all(8),
    ),
    crossAxisCount: 5,
);

Custom

GroupedListView(
    items: List<int>.generate(100, (index) => index + 1),
    headerBuilder: (context, bool isEven) => Container(
        child: Text(
            isEven ? 'Even' : 'Odd',
            style: const TextStyle(fontWeight: FontWeight.bold),
        ),
        padding: const EdgeInsets.all(16),
    ),
    itemsBuilder: (context, List<IndexedItem<int>> items) => ListView.builder(
        itemCount: items.length,
        shrinkWrap: true,
        physics: const NeverScrollableScrollPhysics(),
        itemBuilder: (context, int index) => Container(
            child: Text(items[index].item.toRadixString(10),
                textAlign: TextAlign.center),
            padding: const EdgeInsets.all(8),
        ),
    ),
    itemGrouper: (int i) => i.isEven,
);

Sticky Header

GroupedListView(
    items: List<int>.generate(100, (index) => index + 1),
    customBuilder: (context, bool isEvenHeader, List<IndexedItem<int>> items) => StickyHeader(
        header: Container(
        color: Colors.amber,
        child: Text(
            isEvenHeader ? 'Even' : 'Odd',
            style: const TextStyle(fontWeight: FontWeight.bold),
        ),
        padding: const EdgeInsets.all(16)),
        content: ListView.builder(
            itemCount: items.length,
            shrinkWrap: true,
            physics: const NeverScrollableScrollPhysics(),
            itemBuilder: (context, int index) => Container(
                child: Text(items[index].item.toRadixString(10),
                    textAlign: TextAlign.center),
                padding: const EdgeInsets.all(8),
            ),
        ),
    ),
    itemGrouper: (int i) => i.isEven,
)

完整示例Demo

下面是一个完整的示例应用程序,展示了如何使用 simple_grouped_listview 插件创建不同的分组列表视图。

import 'package:flutter/material.dart';
import 'package:simple_grouped_listview/simple_grouped_listview.dart';
import 'package:sticky_headers/sticky_headers.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: [
          ElevatedButton(
            child: const Text('Custom'),
            onPressed: () => Navigator.push(
                context, MaterialPageRoute(builder: (_) => const CustomPage())),
          ),
          ElevatedButton(
            child: const Text('ListView'),
            onPressed: () => Navigator.push(
                context, MaterialPageRoute(builder: (_) => const ListPage())),
          ),
          ElevatedButton(
            child: const Text('GridView'),
            onPressed: () => Navigator.push(
                context, MaterialPageRoute(builder: (_) => const GridPage())),
          ),
          ElevatedButton(
            child: const Text('Sticky Header'),
            onPressed: () => Navigator.push(
                context, MaterialPageRoute(builder: (_) => const StickyPage())),
          ),
          ElevatedButton(
            child: const Text('Horizontal Page'),
            onPressed: () => Navigator.push(context,
                MaterialPageRoute(builder: (_) => const HorizontalPage())),
          ),
        ],
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Custom GroupedListView')),
      body: GroupedListView(
        items: List<int>.generate(100, (index) => index + 1),
        headerBuilder: (context, bool isEven) {
          return Container(
            color: Colors.amber,
            child: Text(
              isEven ? 'Even' : 'Odd',
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
            padding: const EdgeInsets.all(16),
          );
        },
        itemsBuilder: (context, List<IndexedItem<int>> items) {
          return ListView.builder(
              itemCount: items.length,
              shrinkWrap: true,
              physics: const NeverScrollableScrollPhysics(),
              itemBuilder: (context, int index) {
                return Container(
                  color: Color.fromARGB(
                    255,
                    ((128 / items.length) * index).toInt() + 127,
                    ((128 / items.length) * index).toInt() + 127,
                    ((128 / items.length) * index).toInt() + 127,
                  ),
                  child: Text(items[index].item.toRadixString(10),
                      textAlign: TextAlign.center),
                  padding: const EdgeInsets.all(8),
                );
              });
        },
        itemGrouper: (int i) => i.isEven,
        itemsCrossAxisAlignment: CrossAxisAlignment.center,
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('GroupedListView.list()')),
      body: GroupedListView.list(
        items: List<int>.generate(100, (index) => index + 1),
        headerBuilder: (context, bool isEven) {
          return Container(
            color: Colors.amber,
            child: Text(
              isEven ? 'Even' : 'Odd',
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
            padding: const EdgeInsets.all(16),
          );
        },
        listItemBuilder:
            (context, int countInGroup, int itemIndexInGroup, int item, _) =>
                Container(
          color: Color.fromARGB(
            255,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
          ),
          child: Text(item.toRadixString(10), textAlign: TextAlign.center),
          padding: const EdgeInsets.all(8),
        ),
        itemGrouper: (int i) => i.isEven,
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('GroupedListView.grid()')),
      body: GroupedListView.grid(
        items: List<int>.generate(100, (index) => index + 1),
        headerBuilder: (context, bool isEven) {
          return Container(
            color: Colors.amber,
            child: Text(
              isEven ? 'Event' : 'Odd',
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
            padding: const EdgeInsets.all(16),
          );
        },
        gridItemBuilder:
            (context, int countInGroup, int itemIndexInGroup, int item, _) =>
                Container(
          color: Color.fromARGB(
            255,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
          ),
          child: Text(item.toRadixString(10), textAlign: TextAlign.center),
          padding: const EdgeInsets.all(8),
        ),
        itemGrouper: (int i) => i.isEven,
        crossAxisCount: 5,
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar:
          AppBar(title: const Text('Custom GroupedListView with StickyHeader')),
      body: GroupedListView<bool, int>(
        items: List<int>.generate(100, (index) => index + 1),
        customBuilder:
            (context, bool isEvenHeader, List<IndexedItem<int>> items) {
          return StickyHeader(
              header: Container(
                color: Colors.amber,
                child: Text(
                  isEvenHeader ? 'Even' : 'Odd',
                  style: const TextStyle(fontWeight: FontWeight.bold),
                ),
                padding: const EdgeInsets.all(16),
              ),
              content: ListView.builder(
                  itemCount: items.length,
                  shrinkWrap: true,
                  physics: const NeverScrollableScrollPhysics(),
                  itemBuilder: (context, int index) {
                    return Container(
                      color: Color.fromARGB(
                        255,
                        ((128 / items.length) * index).toInt() + 127,
                        ((128 / items.length) * index).toInt() + 127,
                        ((128 / items.length) * index).toInt() + 127,
                      ),
                      child: Text(items[index].item.toRadixString(10),
                          textAlign: TextAlign.center),
                      padding: const EdgeInsets.all(8),
                    );
                  }));
        },
        itemGrouper: (int i) => i.isEven,
        itemsCrossAxisAlignment: CrossAxisAlignment.center,
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: const Text(
              'GroupedListView.list() GroupedListView horizontal Page')),
      body: GroupedListView.list(
        shrinkWrap: true,
        scrollDirection: Axis.horizontal,
        items: List<int>.generate(100, (index) => index + 1),
        itemGrouper: (int i) => i.isEven,
        headerBuilder: (context, bool isEven) => Text(isEven ? 'Even' : 'Odd'),
        listItemBuilder:
            (context, int countInGroup, int itemIndexInGroup, int item, _) =>
                Container(
          color: Color.fromARGB(
            255,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
            ((128 / countInGroup) * itemIndexInGroup).toInt() + 127,
          ),
          child: Text(item.toRadixString(10), textAlign: TextAlign.center),
          padding: const EdgeInsets.all(8),
        ),
      ),
    );
  }
}

其他信息

如果你有任何问题或建议,欢迎在 GitHub Issues 中提出。希望这个插件能帮助你构建出炫酷的Flutter UI!


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

1 回复

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


当然,以下是如何在Flutter中使用simple_grouped_listview插件来展示分组列表的示例代码。首先,你需要确保已经在你的pubspec.yaml文件中添加了simple_grouped_listview依赖:

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

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

接下来是一个完整的示例代码,展示如何使用simple_grouped_listview来创建一个分组列表:

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

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

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

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

class _MyHomePageState extends State<MyHomePage> {
  // 示例数据
  final List<GroupedItem> groupedItems = [
    GroupedItem(
      title: 'Group 1',
      items: [
        Item(id: '1-1', title: 'Item 1-1'),
        Item(id: '1-2', title: 'Item 1-2'),
      ],
    ),
    GroupedItem(
      title: 'Group 2',
      items: [
        Item(id: '2-1', title: 'Item 2-1'),
        Item(id: '2-2', title: 'Item 2-2'),
        Item(id: '2-3', title: 'Item 2-3'),
      ],
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Grouped ListView Demo'),
      ),
      body: SimpleGroupedListView(
        groupedItems: groupedItems,
        onItemClick: (Item item) {
          // 处理点击事件
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content: Text('Clicked on ${item.title}'),
            ),
          );
        },
        onGroupExpandCollapse: (String groupTitle, bool isExpanded) {
          // 处理分组展开/折叠事件
          print('Group $groupTitle is now $isExpanded');
        },
        // 可选参数:自定义分组标题和项的样式
        groupHeaderBuilder: (BuildContext context, String groupTitle) {
          return Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
            child: Text(
              groupTitle,
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
          );
        },
        itemBuilder: (BuildContext context, Item item) {
          return ListTile(
            title: Text(item.title),
          );
        },
      ),
    );
  }
}

// 定义分组和项的模型
class GroupedItem {
  final String title;
  final List<Item> items;

  GroupedItem({required this.title, required this.items});
}

class Item {
  final String id;
  final String title;

  Item({required this.id, required this.title});
}

在这个示例中,我们定义了两个模型类GroupedItemItem,分别表示分组和分组内的项。GroupedItem包含分组的标题和该分组下的项列表。Item包含项的ID和标题。

MyHomePage类中,我们创建了一个包含示例数据的groupedItems列表,并使用SimpleGroupedListView小部件来展示这些数据。我们还定义了点击项和分组展开/折叠时的回调函数。

SimpleGroupedListView的参数包括:

  • groupedItems:分组和项的列表。
  • onItemClick:点击项时的回调函数。
  • onGroupExpandCollapse:分组展开或折叠时的回调函数。
  • groupHeaderBuilder:自定义分组标题的样式(可选)。
  • itemBuilder:自定义项的样式(可选)。

这个示例展示了如何使用simple_grouped_listview插件来创建一个具有分组功能的列表视图,并处理用户交互。

回到顶部