[英]Is there an equivalent widget in flutter to the "select multiple" element in HTML
I am searching for a widget in flutter that is equal to我在颤振中寻找一个小部件,它等于
<select multiple=""></select>
in flutter.在颤抖。
An example implementation (for the web) is MaterializeCSS Select Multiple一个示例实现(用于网络)是MaterializeCSS Select Multiple
As seen above I should be able to provide a list of items (with some of them preselected) and at the end retrieve a list of selected items or a map or something else.如上所述,我应该能够提供一个项目列表(其中一些是预选的),最后检索所选项目的列表或地图或其他东西。
An example implementation or a link to a documentation is very appreciated.非常感谢示例实现或指向文档的链接。
I don't think that a widget like that currently exists in Flutter, but you can build one yourself.我认为 Flutter 中目前不存在这样的小部件,但您可以自己构建一个。
On mobile phones with limited screen space it would probably make sense to display a dialog with a submit button, like this native Android dialog .在屏幕空间有限的手机上,显示一个带有提交按钮的对话框可能是有意义的,比如这个原生 Android 对话框。
Here is a rough sketch how to implement such a dialog in less than 100 lines of code:以下是如何用不到 100 行代码实现这样一个对话框的粗略草图:
class MultiSelectDialogItem<V> {
const MultiSelectDialogItem(this.value, this.label);
final V value;
final String label;
}
class MultiSelectDialog<V> extends StatefulWidget {
MultiSelectDialog({Key key, this.items, this.initialSelectedValues}) : super(key: key);
final List<MultiSelectDialogItem<V>> items;
final Set<V> initialSelectedValues;
@override
State<StatefulWidget> createState() => _MultiSelectDialogState<V>();
}
class _MultiSelectDialogState<V> extends State<MultiSelectDialog<V>> {
final _selectedValues = Set<V>();
void initState() {
super.initState();
if (widget.initialSelectedValues != null) {
_selectedValues.addAll(widget.initialSelectedValues);
}
}
void _onItemCheckedChange(V itemValue, bool checked) {
setState(() {
if (checked) {
_selectedValues.add(itemValue);
} else {
_selectedValues.remove(itemValue);
}
});
}
void _onCancelTap() {
Navigator.pop(context);
}
void _onSubmitTap() {
Navigator.pop(context, _selectedValues);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Select animals'),
contentPadding: EdgeInsets.only(top: 12.0),
content: SingleChildScrollView(
child: ListTileTheme(
contentPadding: EdgeInsets.fromLTRB(14.0, 0.0, 24.0, 0.0),
child: ListBody(
children: widget.items.map(_buildItem).toList(),
),
),
),
actions: <Widget>[
FlatButton(
child: Text('CANCEL'),
onPressed: _onCancelTap,
),
FlatButton(
child: Text('OK'),
onPressed: _onSubmitTap,
)
],
);
}
Widget _buildItem(MultiSelectDialogItem<V> item) {
final checked = _selectedValues.contains(item.value);
return CheckboxListTile(
value: checked,
title: Text(item.label),
controlAffinity: ListTileControlAffinity.leading,
onChanged: (checked) => _onItemCheckedChange(item.value, checked),
);
}
}
You can use it like this:你可以这样使用它:
void _showMultiSelect(BuildContext context) async {
final items = <MultiSelectDialogItem<int>>[
MultiSelectDialogItem(1, 'Dog'),
MultiSelectDialogItem(2, 'Cat'),
MultiSelectDialogItem(3, 'Mouse'),
];
final selectedValues = await showDialog<Set<int>>(
context: context,
builder: (BuildContext context) {
return MultiSelectDialog(
items: items,
initialSelectedValues: [1, 3].toSet(),
);
},
);
print(selectedValues);
}
Try to this to support list of values as dynamic like (dart model/ collection) as a items and also you can get text value in selected value (As @urvashi commented in the above answer)尝试这样做以支持将值列表作为动态(例如(dart 模型/集合))作为项目,并且您还可以获得所选值中的文本值(正如@urvashi 在上述答案中评论的那样)
First of make the model class首先制作模型类
class BuildingModel {
String id;
String number;
String toString() {
return '$id $number';
}
BuildingModel(this.id, this.number);
}
After of make the class as above在使类如上之后
class MultiSelectDialogItem<V> {
const MultiSelectDialogItem(this.value, this.label);
final V value;
final String label;
}
class MultiSelectDialog<V> extends StatefulWidget {
MultiSelectDialog({Key key, this.items, this.initialSelectedValues})
: super(key: key);
final List<MultiSelectDialogItem<V>> items;
final Set<V> initialSelectedValues;
@override
State<StatefulWidget> createState() => _MultiSelectDialogState<V>();
}
class _MultiSelectDialogState<V> extends State<MultiSelectDialog<V>> {
final _selectedValues = Set<V>();
void initState() {
super.initState();
if (widget.initialSelectedValues != null) {
_selectedValues.addAll(widget.initialSelectedValues);
}
}
void _onItemCheckedChange(V itemValue, bool checked) {
setState(() {
if (checked) {
_selectedValues.add(itemValue);
} else {
_selectedValues.remove(itemValue);
}
});
}
void _onCancelTap() {
Navigator.pop(context);
}
void _onSubmitTap() {
Navigator.pop(context, _selectedValues);
}
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Select wing'),
contentPadding: EdgeInsets.only(top: 12.0),
content: SingleChildScrollView(
child: ListTileTheme(
contentPadding: EdgeInsets.fromLTRB(14.0, 0.0, 24.0, 0.0),
child: ListBody(
children: widget.items.map(_buildItem).toList(),
),
),
),
actions: <Widget>[
FlatButton(
child: Text('CANCEL'),
onPressed: _onCancelTap,
),
FlatButton(
child: Text('SAVE'),
onPressed: _onSubmitTap,
)
],
);
}
Widget _buildItem(MultiSelectDialogItem<V> item) {
final checked = _selectedValues.contains(item.value);
return CheckboxListTile(
value: checked,
title: Text(item.label),
controlAffinity: ListTileControlAffinity.leading,
onChanged: (checked) => _onItemCheckedChange(item.value, checked),
);
}
}
void _showMultiSelect(BuildContext context) async {
final items = buildingDropdownItems;
final selectedValues = await showDialog<Set<BuildingModel>>(
context: context,
builder: (BuildContext context) {
return MultiSelectDialog(
items: items,
);
},
);
selectedValues.forEach((element) {
print(element.id);
});
}
}
Then finally you implement like this, ( don't forget to change showDialog data type It should be your item type showDialog<Set<BuildingModel>>
)然后最后你这样实现,(不要忘记改变 showDialog 数据类型它应该是你的项目类型showDialog<Set<BuildingModel>>
)
void _showMultiSelect(BuildContext context) async {
final items = buildingDropdownItems;
final selectedValues = await showDialog<Set<BuildingModel>>(
context: context,
builder: (BuildContext context) {
return MultiSelectDialog(
items: items,
);
},
);
// here print your value or use per your need
selectedValues.forEach((element) {
print(element.id);
print(element.number);
});
}
}
Is this what you want?这是你想要的吗?
In case you need a short and ready to use code, follow this article如果你需要一个短期和准备使用的代码,请按照此文章
import 'package:flutter/material.dart';
import 'package:multiple_selection_dialogue_app/widgets/multi_select_dialog.dart';
/// A demo page that displays an [ElevatedButton]
class DemoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
/// Stores the selected flavours
List<String> flavours = [];
return ElevatedButton(
child: Text('Flavours'),
onPressed: () async {
flavours = await showDialog<List<String>>(
context: context,
builder: (_) => MultiSelectDialog(
question: Text('Select Your Flavours'),
answers: [
'Chocolate',
'Caramel',
'Vanilla',
'Peanut Butter'
])) ??
[];
print(flavours);
// Logic to save selected flavours in the database
});
}
}
import 'package:flutter/material.dart';
/// A Custom Dialog that displays a single question & list of answers.
class MultiSelectDialog extends StatelessWidget {
/// List to display the answer.
final List<String> answers;
/// Widget to display the question.
final Widget question;
/// List to hold the selected answer
/// i.e. ['a'] or ['a','b'] or ['a','b','c'] etc.
final List<String> selectedItems = [];
/// Map that holds selected option with a boolean value
/// i.e. { 'a' : false}.
static Map<String, bool> mappedItem;
MultiSelectDialog({this.answers, this.question});
/// Function that converts the list answer to a map.
Map<String, bool> initMap() {
return mappedItem = Map.fromIterable(answers,
key: (k) => k.toString(),
value: (v) {
if (v != true && v != false)
return false;
else
return v as bool;
});
}
@override
Widget build(BuildContext context) {
if (mappedItem == null) {
initMap();
}
return SimpleDialog(
title: question,
children: [
...mappedItem.keys.map((String key) {
return StatefulBuilder(
builder: (_, StateSetter setState) => CheckboxListTile(
title: Text(key), // Displays the option
value: mappedItem[key], // Displays checked or unchecked value
controlAffinity: ListTileControlAffinity.platform,
onChanged: (value) => setState(() => mappedItem[key] = value)),
);
}).toList(),
Align(
alignment: Alignment.center,
child: ElevatedButton(
style: ButtonStyle(visualDensity: VisualDensity.comfortable),
child: Text('Submit'),
onPressed: () {
// Clear the list
selectedItems.clear();
// Traverse each map entry
mappedItem.forEach((key, value) {
if (value == true) {
selectedItems.add(key);
}
});
// Close the Dialog & return selectedItems
Navigator.pop(context, selectedItems);
}))
],
);
}
}
import 'package:flutter/material.dart';
import 'package:multiple_selection_dialogue_app/pages/demo_page.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: DemoPage(),
),
),
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.