Flutter中如何基于两种方案实现分组多选下拉框?
Flutter 实现带分组标题的多选下拉框
下面提供两种实现方案,分别基于第三方包和自定义实现,都能达到你需要的分组多选效果:
方案一:使用 multi_select_flutter 包
步骤1:添加依赖
在 pubspec.yaml 中引入包:
dependencies: multi_select_flutter: ^4.1.0 # 建议使用最新版本
步骤2:实现分组多选逻辑
通过自定义 itemBuilder 插入分组标题,示例代码如下:
import 'package:flutter/material.dart'; import 'package:multi_select_flutter/multi_select_flutter.dart'; class GroupedMultiSelectPage extends StatefulWidget { const GroupedMultiSelectPage({Key? key}) : super(key: key); @override State<GroupedMultiSelectPage> createState() => _GroupedMultiSelectPageState(); } class _GroupedMultiSelectPageState extends State<GroupedMultiSelectPage> { // 定义分组数据结构 final List<GroupedItem> groupedItems = [ GroupedItem( groupTitle: "水果", items: [ MultiSelectItem<String>("苹果", "苹果"), MultiSelectItem<String>("香蕉", "香蕉"), MultiSelectItem<String>("橙子", "橙子"), ], ), GroupedItem( groupTitle: "蔬菜", items: [ MultiSelectItem<String>("白菜", "白菜"), MultiSelectItem<String>("胡萝卜", "胡萝卜"), MultiSelectItem<String>("西兰花", "西兰花"), ], ), ]; List<String> selectedItems = []; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("分组多选下拉框")), body: Padding( padding: const EdgeInsets.all(16.0), child: MultiSelectBottomSheetField( initialValue: selectedItems, title: const Text("选择选项"), buttonText: const Text("打开选择器"), items: groupedItems.expand((group) => group.items).toList(), listType: MultiSelectListType.CHIP, onConfirm: (values) { setState(() { selectedItems = values.cast<String>(); }); }, // 自定义列表项,插入分组标题 itemBuilder: (context, item, isSelected) { final group = groupedItems.firstWhere((g) => g.items.contains(item)); final isFirstInGroup = group.items.first == item; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 仅在分组第一个元素前显示标题 if (isFirstInGroup) Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: Text( group.groupTitle, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), MultiSelectItem( item: item.value, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Text(item.label), ), ), ], ); }, ), ), ); } } // 分组数据模型 class GroupedItem { final String groupTitle; final List<MultiSelectItem<String>> items; GroupedItem({required this.groupTitle, required this.items}); }
方案二:自定义实现分组多选
如果不想依赖第三方包,可以通过 AlertDialog + ListView 自定义实现:
import 'package:flutter/material.dart'; class CustomGroupedMultiSelect extends StatefulWidget { final List<GroupedOption> groupedOptions; final ValueChanged<List<String>> onSelectedChanged; final List<String> initialSelected; const CustomGroupedMultiSelect({ Key? key, required this.groupedOptions, required this.onSelectedChanged, required this.initialSelected, }) : super(key: key); @override State<CustomGroupedMultiSelect> createState() => _CustomGroupedMultiSelectState(); } class _CustomGroupedMultiSelectState extends State<CustomGroupedMultiSelect> { late List<String> _selectedItems; @override void initState() { super.initState(); _selectedItems = List.from(widget.initialSelected); } void _toggleSelection(String item) { setState(() { _selectedItems.contains(item) ? _selectedItems.remove(item) : _selectedItems.add(item); }); } @override Widget build(BuildContext context) { return ElevatedButton( onPressed: _showMultiSelectDialog, child: Text(_selectedItems.isEmpty ? "选择选项" : "已选: ${_selectedItems.join(', ')}"), ); } void _showMultiSelectDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text("选择选项"), content: SizedBox( width: double.maxFinite, height: 300, child: ListView.builder( itemCount: widget.groupedOptions.length, itemBuilder: (context, groupIndex) { final group = widget.groupedOptions[groupIndex]; return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 分组标题 Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: Text( group.groupTitle, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ), // 分组下的多选选项 ...group.options.map((option) => CheckboxListTile( title: Text(option), value: _selectedItems.contains(option), onChanged: (checked) => checked != null ? _toggleSelection(option) : null, )), ], ); }, ), ), actions: [ TextButton(onPressed: () => Navigator.pop(context), child: const Text("取消")), TextButton( onPressed: () { widget.onSelectedChanged(_selectedItems); Navigator.pop(context); }, child: const Text("确认"), ), ], ), ); } } // 分组选项模型 class GroupedOption { final String groupTitle; final List<String> options; GroupedOption({required this.groupTitle, required this.options}); } // 使用示例 class CustomMultiSelectPage extends StatelessWidget { const CustomMultiSelectPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final groupedOptions = [ GroupedOption(groupTitle: "水果", options: ["苹果", "香蕉", "橙子"]), GroupedOption(groupTitle: "蔬菜", options: ["白菜", "胡萝卜", "西兰花"]), ]; return Scaffold( appBar: AppBar(title: const Text("自定义分组多选下拉框")), body: Padding( padding: const EdgeInsets.all(16.0), child: CustomGroupedMultiSelect( groupedOptions: groupedOptions, initialSelected: [], onSelectedChanged: (selected) => print("已选: $selected"), ), ), ); } }
内容的提问来源于stack exchange,提问作者Khalid
相关产品推荐
相关产品推荐

