一、下拉框多选内容,允许限制指定数量以后其他选择变不可选中。效果如图:

二、代码

1、下拉款弹窗效果:文件路径:/components/multi_select/common_multi_select_dialog.dart

import 'package:flutter/material.dart';

class CommonMultiSelectDialog extends StatefulWidget {
  final List<String> items;
  final List<String> selected;
  final int maxSelect;

  const CommonMultiSelectDialog({
    super.key,
    required this.items,
    required this.selected,
    required this.maxSelect,
  });

  @override
  State<CommonMultiSelectDialog> createState() =>
      _CommonMultiSelectDialogState();
}

class _CommonMultiSelectDialogState extends State<CommonMultiSelectDialog> {
  late List<String> _selected;
  String _keyword = "";

  @override
  void initState() {
    super.initState();
    _selected = List.from(widget.selected);
  }

  bool _canSelect(String item) {
    // 已选的永远可点(用于取消)
    if (_selected.contains(item)) return true;
    // 未选的:只有没满才能选
    return _selected.length < widget.maxSelect;
  }

  @override
  Widget build(BuildContext context) {
    final list = widget.items
        .where((e) => e.contains(_keyword))
        .toList();

    return Dialog(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          // 🔍 搜索
          Padding(
            padding: const EdgeInsets.all(12),
            child: TextField(
              decoration: const InputDecoration(
                hintText: "搜索",
                isDense: true,
                border: OutlineInputBorder(),
              ),
              onChanged: (v) {
                setState(() => _keyword = v);
              },
            ),
          ),

          // 📋 列表
          Flexible(
            child: ListView.builder(
              shrinkWrap: true,
              itemCount: list.length,
              itemBuilder: (_, index) {
                final item = list[index];
                final selected = _selected.contains(item);
                final enabled = _canSelect(item);

                return CheckboxListTile(
                  value: selected,
                  title: Text(
                    item,
                    style: TextStyle(
                      color: enabled ? Colors.black : Colors.grey,
                    ),
                  ),
                  onChanged: enabled
                      ? (v) {
                          setState(() {
                            if (v == true) {
                              _selected.add(item);
                            } else {
                              _selected.remove(item);
                            }
                          });
                        }
                      : null, // 🚫 直接禁用
                );
              },
            ),
          ),

          // ⬇️ 底部操作
          Padding(
            padding: const EdgeInsets.all(12),
            child: Row(
              children: [
                Expanded(
                  child: Text(
                    "已选 ${_selected.length}/${widget.maxSelect}",
                    style: const TextStyle(fontSize: 12),
                  ),
                ),
                TextButton(
                  onPressed: () => Navigator.pop(context),
                  child: const Text("取消"),
                ),
                ElevatedButton(
                  onPressed: () => Navigator.pop(context, _selected),
                  child: const Text("确定"),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

二、左侧图标右侧下拉框内容。效果如图:

import 'package:flutter/material.dart';
import 'package:components/multi_select/common_multi_select_dialog.dart';

class IconMultiSelectInput extends StatefulWidget {
  final String placeholder;
  final IconData prefixIcon;
  final List<String> items;
  final int maxSelect;
  final List<String> cateChooseItems;
  final ValueChanged<List<String>>? onChanged;

  const IconMultiSelectInput({
    super.key,
    required this.placeholder,
    required this.prefixIcon,
    required this.items,
    required this.cateChooseItems,
    this.maxSelect = 3,
    this.onChanged,
  });

  @override
  State<IconMultiSelectInput> createState() => _IconMultiSelectInputState();
}

class _IconMultiSelectInputState extends State<IconMultiSelectInput> {
  String showText="";
  List<String> _selected = [];

  Future<void> _openDialog() async {
    final result = await showDialog<List<String>>(
      context: context,
      builder: (_) => CommonMultiSelectDialog(
        items: widget.items,
        selected: _selected,
        maxSelect: widget.maxSelect,
      ),
    );

    if (result != null) {
      setState(() {
        _selected = result;
        print("选择的内容 ${_selected}");
        showText = result.join(" / ");
        widget.cateChooseItems=showText;
      });
      widget.onChanged?.call(result);
    }
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: _openDialog,
      child: Container(
        height: 36,
        padding: const EdgeInsets.symmetric(horizontal: 12),
        decoration: BoxDecoration(
          border: Border.all(color: const Color(0xFFd1d5db)),
          borderRadius: BorderRadius.circular(4),
        ),
        child: Row(
          children: [
            Icon(widget.prefixIcon, size: 20, color: const Color(0xFF9CA3AF)),
            const SizedBox(width: 8),
            Expanded(
              child: Text(
                showText.isEmpty
                    ? widget.placeholder
                    : showText,
                style: TextStyle(
                  fontSize: 14,
                  color: showText.isEmpty
                      ? const Color(0xFF9CA3AF)
                      : Colors.black,
                ),
                overflow: TextOverflow.ellipsis,
              ),
            ),
            const Icon(Icons.keyboard_arrow_down),
          ],
        ),
      ),
    );
  }
}

3、页面调用代码:

final List<String> cateChooseItems=[];
IconMultiSelectInput(
            placeholder: "行业",
            prefixIcon: Icons.memory,
            maxSelect: 3,
            items: [
              "互联网",
              "制造业",
              "金融",
              "医疗",
              "教育",
              "农业",
              "互联网1",
              "制造业1",
              "金融1",
              "医疗1",
              "教育1",
              "农业1",
            ],
            cateChooseItems: widget.cateChooseItems,
            onChanged: (list) {
              print("++++++++++++++");
              print(list);
            },
          )

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐