Flutter分组列表展示插件simple_grouped_listview的使用
Flutter分组列表展示插件simple_grouped_listview的使用
简介
simple_grouped_listview
是一个Flutter插件,用于在ListView中显示分组项目。通过这个插件,你可以轻松地将列表项按照某种规则进行分组,并且可以自定义分组头和列表项的样式。
使用场景
有时候你有一个 List<T>
并且希望以某种特定的方式显示它。例如,T
有一个 DateTime
字段,你想根据年、月、日或混合方式对它们进行分组。使用这个插件,你可以轻松实现这些需求。
主要特性
- Custom Grouped ListView:带有头部构建器和列表项构建器。
- List Grouped ListView:带有头部构建器和每个列表项的构建器。
- Grid Grouped ListView:带有头部构建器和每个网格项的构建器。
- Custom Grouped ListView with Custom Builder:为每个分组项(头部和列表项)提供构建器。
这些功能可以帮助你创建如下的效果:
安装
添加依赖
在你的 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
更多关于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});
}
在这个示例中,我们定义了两个模型类GroupedItem
和Item
,分别表示分组和分组内的项。GroupedItem
包含分组的标题和该分组下的项列表。Item
包含项的ID和标题。
在MyHomePage
类中,我们创建了一个包含示例数据的groupedItems
列表,并使用SimpleGroupedListView
小部件来展示这些数据。我们还定义了点击项和分组展开/折叠时的回调函数。
SimpleGroupedListView
的参数包括:
groupedItems
:分组和项的列表。onItemClick
:点击项时的回调函数。onGroupExpandCollapse
:分组展开或折叠时的回调函数。groupHeaderBuilder
:自定义分组标题的样式(可选)。itemBuilder
:自定义项的样式(可选)。
这个示例展示了如何使用simple_grouped_listview
插件来创建一个具有分组功能的列表视图,并处理用户交互。