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

二、代码
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);
},
)
更多推荐
所有评论(0)