Flutter:使用复选框进行下拉多选
本文向您展示了在 Flutter 中使用复选框实现下拉多选的两种不同方法。在第一种方法中,我们将从头开始构建多选。在第二种方法中,我们将使用第三方包快速完成工作。
从头开始使用复选框创建多选
应用预览
image-20220102224407863
我们将要构建的应用程序有一个专业的、功能齐全的多选小部件,可显示选项列表。可以通过选中/取消选中与其关联的复选框来选择或取消选择一个选项。
当按下升高的按钮时,将显示多选对话框。它让用户在编程中选择他们最喜欢的主题。所选主题将作为筹码显示在屏幕上。
以下是我们的应用程序的运行方式:
构建自定义多选小部件
创建一个名为MultiSelect的可重用小部件,它可以获取选项列表(您可以对这些项目进行硬编码或从数据库/API 中获取它们):
代码语言:javascript复制// Multi Select widget
// This widget is reusable
class MultiSelect extends StatefulWidget {
final List<String> items;
const MultiSelect({Key? key, required this.items}) : super(key: key);
@override
State<StatefulWidget> createState() => _MultiSelectState();
}
class _MultiSelectState extends State<MultiSelect> {
// this variable holds the selected items
final List<String> _selectedItems = [];
// This function is triggered when a checkbox is checked or unchecked
void _itemChange(String itemValue, bool isSelected) {
setState(() {
if (isSelected) {
_selectedItems.add(itemValue);
} else {
_selectedItems.remove(itemValue);
}
});
}
// this function is called when the Cancel button is pressed
void _cancel() {
Navigator.pop(context);
}
// this function is called when the Submit button is tapped
void _submit() {
Navigator.pop(context, _selectedItems);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Select Topics'),
content: SingleChildScrollView(
child: ListBody(
children: widget.items
.map((item) => CheckboxListTile(
value: _selectedItems.contains(item),
title: Text(item),
controlAffinity: ListTileControlAffinity.leading,
onChanged: (isChecked) => _itemChange(item, isChecked!),
))
.toList(),
),
),
actions: [
TextButton(
child: const Text('Cancel'),
onPressed: _cancel,
),
ElevatedButton(
child: const Text('Submit'),
onPressed: _submit,
),
],
);
}
}
完整的代码
这是您在上面的演示中看到的应用程序的代码:
代码语言:javascript复制import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
const String title = "坚果";
return MaterialApp(
debugShowCheckedModeBanner: false,
title: title,
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: const HomePage(),
);
}
}
// Multi Select widget
// This widget is reusable
class MultiSelect extends StatefulWidget {
final List<String> items;
const MultiSelect({Key? key, required this.items}) : super(key: key);
@override
State<StatefulWidget> createState() => _MultiSelectState();
}
class _MultiSelectState extends State<MultiSelect> {
// this variable holds the selected items
final List<String> _selectedItems = [];
// This function is triggered when a checkbox is checked or unchecked
void _itemChange(String itemValue, bool isSelected) {
setState(() {
if (isSelected) {
_selectedItems.add(itemValue);
} else {
_selectedItems.remove(itemValue);
}
});
}
// this function is called when the Cancel button is pressed
void _cancel() {
Navigator.pop(context);
}
// this function is called when the Submit button is tapped
void _submit() {
Navigator.pop(context, _selectedItems);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('Select Topics'),
content: SingleChildScrollView(
child: ListBody(
children: widget.items
.map((item) => CheckboxListTile(
value: _selectedItems.contains(item),
title: Text(item),
controlAffinity: ListTileControlAffinity.leading,
onChanged: (isChecked) => _itemChange(item, isChecked!),
))
.toList(),
),
),
actions: [
TextButton(
child: const Text('取消'),
onPressed: _cancel,
),
ElevatedButton(
child: const Text('确定'),
onPressed: _submit,
),
],
);
}
}
// Implement a multi select on the Home screen
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<String> _selectedItems = [];
String _title = "坚果";
void _showMultiSelect() async {
// a list of selectable items
// these items can be hard-coded or dynamically fetched from a database/API
final List<String> _items = [
'Flutter',
'Node.js',
'React Native',
'Java',
'Docker',
'MySQL'
];
final List<String>? results = await showDialog(
context: context,
builder: (BuildContext context) {
return MultiSelect(items: _items);
},
);
// Update UI
if (results != null) {
setState(() {
_selectedItems = results;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// use this button to open the multi-select dialog
ElevatedButton(
child: const Text('选出你最喜欢的技术'),
onPressed: _showMultiSelect,
),
const Divider(
height: 30,
),
// display selected items
Wrap(
children: _selectedItems
.map((e) => Chip(
label: Text(e),
))
.toList(),
)
],
),
),
);
}
}
使用第三方插件
进行自定义多选既不复杂也不复杂。但是,如果您有紧急任务并且只想尽快进行多选,那么使用第三方插件是一个不错的选择。有几个不错的开源包供您使用:
- flutter_multi_select
- multiselect_formfield
- flutter_multiselect
- multiselect