Flutter 中的 DropdownButton 中有多个 Select
Multiple Select in DropdownButton in flutter
我知道有很多方法/包可以在 flutter 的下拉按钮中实现 multi select -->
但是以我的小知识,我想为基础建设重新发明轮子!!!
我的场景 ->
我有一个 json 格式的位置列表 -->
[{id: 928, location: Amtoli}, {id: 905, location: Ashok Tala}, {id: 899, location: Badur Tola}]
和两个List -->
List _location = new List(); // this comes from API;
List _multiSelectLoc = new List();
并且在 DropDownButton
的 onChanged
属性 -->
onChanged: (newValue) {
setState(() {
_location.forEach((e) {
if (e["id"] == newValue.toString()) {
_multiSelectLoc.add(e);
print(_multiSelectLoc);
}
});
_location.removeWhere(
(e) => e['id'] == newValue.toString());
print(_location);
});
},
我很想知道为什么我的代码不起作用,为什么我不能从 List _location 中删除数据,也不能添加到 List _multiSelectLoc
我已经在 dartpad 中模拟了这种情况,而且它很好!
您可以使用自定义小部件来完成此操作,例如:
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),
);
}
}
之后使用如下:
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);
}
我想我发现了问题,
重写代码 -->
onChanged: (newValue) {
_location.forEach((e) {
if (e['id'].toString() == newValue.toString()) {
_multiSelectLoc.add(e);
// print(_multiSelectLoc);
}
});
_location.removeWhere(
(e) => e['id'].toString() == newValue.toString());
setState(() {
// print(_location);
});
},
我认为问题是,我使用动态类型与字符串类型进行比较,当我添加 .toString()
代码开始给我结果!
我知道有很多方法/包可以在 flutter 的下拉按钮中实现 multi select -->
我的场景 ->
我有一个 json 格式的位置列表 -->
[{id: 928, location: Amtoli}, {id: 905, location: Ashok Tala}, {id: 899, location: Badur Tola}]
和两个List -->
List _location = new List(); // this comes from API;
List _multiSelectLoc = new List();
并且在 DropDownButton
的 onChanged
属性 -->
onChanged: (newValue) {
setState(() {
_location.forEach((e) {
if (e["id"] == newValue.toString()) {
_multiSelectLoc.add(e);
print(_multiSelectLoc);
}
});
_location.removeWhere(
(e) => e['id'] == newValue.toString());
print(_location);
});
},
我很想知道为什么我的代码不起作用,为什么我不能从 List _location 中删除数据,也不能添加到 List _multiSelectLoc
我已经在 dartpad 中模拟了这种情况,而且它很好!
您可以使用自定义小部件来完成此操作,例如:
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),
);
}
}
之后使用如下:
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);
}
我想我发现了问题,
重写代码 -->
onChanged: (newValue) {
_location.forEach((e) {
if (e['id'].toString() == newValue.toString()) {
_multiSelectLoc.add(e);
// print(_multiSelectLoc);
}
});
_location.removeWhere(
(e) => e['id'].toString() == newValue.toString());
setState(() {
// print(_location);
});
},
我认为问题是,我使用动态类型与字符串类型进行比较,当我添加 .toString()
代码开始给我结果!