如何在Flutter中实现三级级联下拉(第三级支持多选复选框)
Flutter 三级级联下拉菜单(第三级支持多选)
1. 定义分类数据模型
先结构化分类数据,明确层级关系:
class Category { final String id; final String name; final List<Category> children; // 子分类 final List<Category>? grandchildren; // 子子分类(第三级) Category({ required this.id, required this.name, this.children = const [], this.grandchildren, }); }
2. 实现级联下拉组件
用StatefulWidget维护选中状态,通过下拉按钮实现一二三级联动,第三级用复选框列表支持多选:
class ThreeLevelCascade extends StatefulWidget { final List<Category> categories; const ThreeLevelCascade({super.key, required this.categories}); @override State<ThreeLevelCascade> createState() => _ThreeLevelCascadeState(); } class _ThreeLevelCascadeState extends State<ThreeLevelCascade> { Category? selectedLevel1; Category? selectedLevel2; Set<Category> selectedLevel3 = {}; // 清空二级、三级选中状态 void _resetLowerLevels() { setState(() { selectedLevel2 = null; selectedLevel3.clear(); }); } // 清空三级选中状态 void _resetLevel3() { setState(() { selectedLevel3.clear(); }); } // 切换第三级选项选中状态 void _toggleLevel3Selection(Category item) { setState(() { if (selectedLevel3.contains(item)) { selectedLevel3.remove(item); } else { selectedLevel3.add(item); } }); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 一级分类下拉 DropdownButtonFormField<Category>( hint: const Text('选择一级分类'), value: selectedLevel1, items: widget.categories.map((cat) { return DropdownMenuItem( value: cat, child: Text(cat.name), ); }).toList(), onChanged: (value) { setState(() { selectedLevel1 = value; _resetLowerLevels(); }); }, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: '一级分类', ), ), const SizedBox(height: 16), // 二级分类下拉(选中一级后显示) if (selectedLevel1 != null) DropdownButtonFormField<Category>( hint: const Text('选择二级分类'), value: selectedLevel2, items: selectedLevel1!.children.map((cat) { return DropdownMenuItem( value: cat, child: Text(cat.name), ); }).toList(), onChanged: (value) { setState(() { selectedLevel2 = value; _resetLevel3(); }); }, decoration: const InputDecoration( border: OutlineInputBorder(), labelText: '二级分类', ), ), const SizedBox(height: 16), // 第三级多选列表(选中二级后显示) if (selectedLevel2 != null && selectedLevel2!.grandchildren != null) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('选择子子分类(可多选)', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500)), const SizedBox(height: 8), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: BorderRadius.circular(4), ), child: ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: selectedLevel2!.grandchildren!.length, itemBuilder: (context, index) { final item = selectedLevel2!.grandchildren![index]; return CheckboxListTile( title: Text(item.name), value: selectedLevel3.contains(item), onChanged: (checked) { if (checked != null) _toggleLevel3Selection(item); }, controlAffinity: ListTileControlAffinity.leading, ); }, ), ), ], ), // 展示选中结果(可选) const SizedBox(height: 24), if (selectedLevel1 != null) Text('选中一级:${selectedLevel1!.name}'), if (selectedLevel2 != null) Text('选中二级:${selectedLevel2!.name}'), if (selectedLevel3.isNotEmpty) Text('选中三级:${selectedLevel3.map((e) => e.name).join(', ')}'), ], ), ); } }
3. 使用组件示例
准备测试数据并在页面中调用:
void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { // 测试分类数据 final testCategories = [ Category( id: '1', name: '电子产品', children: [ Category( id: '1-1', name: '手机', grandchildren: [ Category(id: '1-1-1', name: '苹果'), Category(id: '1-1-2', name: '华为'), Category(id: '1-1-3', name: '小米'), ], ), Category( id: '1-2', name: '电脑', grandchildren: [ Category(id: '1-2-1', name: '笔记本'), Category(id: '1-2-2', name: '台式机'), ], ), ], ), Category( id: '2', name: '服装', children: [ Category( id: '2-1', name: '男装', grandchildren: [ Category(id: '2-1-1', name: 'T恤'), Category(id: '2-1-2', name: '裤子'), ], ), ], ), ]; return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('三级级联多选')), body: ThreeLevelCascade(categories: testCategories), ), ); } }
关键逻辑说明
- 级联联动:选中一级时重置二级、三级状态;选中二级时重置三级状态,保证层级关联正确。
- 多选实现:用
Set<Category>存储第三级选中项,通过CheckboxListTile的状态切换更新集合。 - 条件渲染:仅选中上级分类时才显示对应下级组件,避免无效交互。
内容的提问来源于stack exchange,提问作者Ram Gupta
相关产品推荐
相关产品推荐

