You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 22:55:06