Flutter中用Sticky Group List实现多选及动态AppBar的方法
实现Sticky Group List多选及AppBar状态更新
要实现你需要的功能,核心是通过状态管理维护选中项集合,并在itemBuilder中处理点击事件,动态更新AppBar的内容和操作按钮。以下是具体实现步骤和完整代码:
关键修改点
- 将
MyApp从StatelessWidget改为StatefulWidget,用于维护选中状态 - 添加
Set<Element>存储选中的列表项(用Set避免重复选中) - 给
Element类添加唯一ID并重写相等判断,确保重复内容的项能被正确区分 - 修改
ListTile的点击事件,切换选中状态并更新UI - 动态调整AppBar的标题和操作按钮,根据选中项数量变化展示不同内容
完整代码
import 'package:flutter/material.dart'; import 'package:sticky_grouped_list/sticky_grouped_list.dart'; void main() => runApp(const MyApp()); List<Element> _elements = <Element>[ Element('1', DateTime(2020, 6, 24, 18), 'Got to gym', Icons.fitness_center), Element('2', DateTime(2020, 6, 24, 9), 'Work', Icons.work), Element('3', DateTime(2020, 6, 25, 8), 'Buy groceries', Icons.shopping_basket), Element('4', DateTime(2020, 6, 25, 16), 'Cinema', Icons.movie), Element('5', DateTime(2020, 6, 25, 20), 'Eat', Icons.fastfood), Element('6', DateTime(2020, 6, 26, 12), 'Car wash', Icons.local_car_wash), Element('7', DateTime(2020, 6, 27, 12), 'Car wash', Icons.local_car_wash), Element('8', DateTime(2020, 6, 27, 13), 'Car wash', Icons.local_car_wash), Element('9', DateTime(2020, 6, 27, 14), 'Car wash', Icons.local_car_wash), Element('10', DateTime(2020, 6, 27, 15), 'Car wash', Icons.local_car_wash), Element('11', DateTime(2020, 6, 28, 12), 'Car wash', Icons.local_car_wash), Element('12', DateTime(2020, 6, 29, 12), 'Car wash', Icons.local_car_wash), Element('13', DateTime(2020, 6, 29, 12), 'Car wash', Icons.local_car_wash), Element('14', DateTime(2020, 6, 30, 12), 'Car wash', Icons.local_car_wash), ]; class MyApp extends StatefulWidget { const MyApp({Key? key}) : super(key: key); @override State<MyApp> createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final Set<Element> _selectedElements = {}; @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: Scaffold( appBar: AppBar( title: _selectedElements.isNotEmpty ? Text('已选中 ${_selectedElements.length} 项') : const Text('Grouped List View Example'), actions: [ if (_selectedElements.isNotEmpty) IconButton( icon: const Icon(Icons.delete), onPressed: () { setState(() { // 移除所有选中的项 _elements.removeWhere((e) => _selectedElements.contains(e)); _selectedElements.clear(); }); }, ), if (_selectedElements.isNotEmpty) IconButton( icon: const Icon(Icons.close), onPressed: () { setState(() { // 清空选中状态 _selectedElements.clear(); }); }, ), ], ), body: StickyGroupedListView<Element, DateTime>( elements: _elements, order: StickyGroupedListOrder.ASC, groupBy: (Element element) => DateTime( element.date.year, element.date.month, element.date.day, ), groupComparator: (DateTime value1, DateTime value2) => value2.compareTo(value1), itemComparator: (Element element1, Element element2) => element1.date.compareTo(element2.date), groupSeparatorBuilder: _getGroupSeparator, itemBuilder: (ctx, element) { final isSelected = _selectedElements.contains(element); return Container( // 选中项添加背景色区分 color: isSelected ? Colors.blue[100] : null, child: ListTile( contentPadding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0), leading: Icon(element.icon), title: Text(element.name), trailing: Text('${element.date.hour}:00'), selected: isSelected, onTap: () { setState(() { if (isSelected) { _selectedElements.remove(element); } else { _selectedElements.add(element); } }); }, ), ); }, ), ), ); } Widget _getGroupSeparator(Element element) { return SizedBox( height: 40, child: Container( decoration: BoxDecoration( color: Colors.grey[300], border: Border.all(), ), child: Padding( padding: const EdgeInsets.all(8.0), child: Align( alignment: Alignment.centerLeft, child: Text( '${element.date.day}. ${element.date.month}, ${element.date.year}', textAlign: TextAlign.center, ), ), ), ), ); } } class Element { final String id; DateTime date; String name; IconData icon; Element(this.id, this.date, this.name, this.icon); // 重写相等判断,确保相同ID的元素被视为同一对象 @override bool operator ==(Object other) => identical(this, other) || other is Element && runtimeType == other.runtimeType && id == other.id; @override int get hashCode => id.hashCode; }
功能说明
- 点击任意列表项可切换选中状态,选中项会显示浅蓝色背景
- 当有项被选中时,AppBar标题变为"已选中 X 项",并显示删除和取消按钮
- 点击删除按钮会移除所有选中的项,点击取消按钮会清空选中状态
内容的提问来源于stack exchange,提问作者Irfan Ganatra
相关产品推荐
相关产品推荐

