如何将地图列表作为初始值传递给 flutter_form_builder 包中的 FormBuilder FilterChip?
How to pass a list of maps as inital value to the FormBuilderFilterChip in flutter_form_builder package?
我尝试将 FormBuilderFieldOption 的相同 'value' 字段的列表传递给 initialValue 参数。
编辑:通过列表满足 'required' 验证器但不会将筹码显示为 'marked'
现在,如果我没记错的话,这应该是 return 一组全部标记的筹码,但事实并非如此。
List<Map<String,dynamic>> _allValues = [
{id: 1586762938154, name: 202, rate: 5000, type: 'ABYSS'},
{id: 1586759232569, name: 101, rate: 1000, type: 'DELUXE'},
{id: 1586849439323, name: 13, rate: 3434, type: 'DELUXE'},
{id: 1586759258120, name: 102, rate: 2000, type: 'EXECUTIVE'},
{id: 1586779416843, name: 103, rate: 2343, type: 'EXECUTIVE'},
]
FormBuilderFilterChip(
initialValue: _allValues.map((value) => value).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map((val) => FormBuilderFieldOption(
value: val,
child: Text(val['name']),
),
).toList(),
onChanged: (value) {
_selected = value;
print(_selected);
},
)
您可以复制粘贴 运行 下面的完整代码
假设 _allValues
是 List<Map<String, String>>
代码片段
List<Map<String, String>> _allValues = [
{"name": "abc"},
{"name": "def"},
{"name": "123"}
];
FormBuilderFilterChip(
initialValue:
_allValues.map((value) => value['name']).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map(
(val) => FormBuilderFieldOption(
value: val['name'],
child: Text(val['name']),
),
)
.toList(),
工作演示
完整代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter FormBuilder Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
inputDecorationTheme: InputDecorationTheme(
labelStyle: TextStyle(color: Colors.purple),
),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
MyHomePageState createState() {
return MyHomePageState();
}
}
class Data {
String name;
Data(this.name);
}
class MyHomePageState extends State<MyHomePage> {
var data;
bool autoValidate = true;
bool readOnly = false;
bool showSegmentedControl = true;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
final GlobalKey<FormFieldState> _specifyTextFieldKey =
GlobalKey<FormFieldState>();
ValueChanged _onChanged = (val) => print(val);
var genderOptions = ['Male', 'Female', 'Other'];
List<Map<String, String>> _allValues = [
{"name": "abc"},
{"name": "def"},
{"name": "123"}
];
List<dynamic> _selected;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("FormBuilder Example"),
),
body: Padding(
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(children: <Widget>[
FormBuilder(
// context,
key: _fbKey,
autovalidate: true,
initialValue: {
'movie_rating': 5,
},
readOnly: false,
child: Column(
children: <Widget>[
FormBuilderFilterChip(
initialValue: ["Test 1", "Test 3"],
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: [
FormBuilderFieldOption(
value: 'Test', child: Text('Test')),
FormBuilderFieldOption(
value: 'Test 1', child: Text('Test 1')),
FormBuilderFieldOption(
value: 'Test 2', child: Text('Test 2')),
FormBuilderFieldOption(
value: 'Test 3', child: Text('Test 3')),
FormBuilderFieldOption(
value: 'Test 4', child: Text('Test 4')),
],
),
FormBuilderFilterChip(
initialValue:
_allValues.map((value) => value['name']).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map(
(val) => FormBuilderFieldOption(
value: val['name'],
child: Text(val['name']),
),
)
.toList(),
onChanged: (value) {
_selected = value;
print(_selected);
},
)
],
),
),
]),
)));
}
}
我深入了解了 FormBuilderFilterChip 如何使用 List.contains()方法。
该方法中判断[element]是否等于List中某个元素的相等性默认为该元素的[Object.==]。
因此,为了解决这个问题,我构建了自己的自定义 FilterChipField(从 FormBuilderFilterChip 借用了大部分必要的代码)
FormBuilderCustomField(
attribute: "name",
validators: [
FormBuilderValidators.required(),
],
formField: FormField(
enabled: true,
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
prefixIcon: Icon(Icons.vpn_key),
labelText: "Assign Room(s)",
contentPadding: EdgeInsets.only(top: 10.0, bottom: 0.0),
errorText: field.errorText,
),
child: Container(
child: _buildChipSelectField(field),
),
);
},
),
)
下面的_buildChipSelectField包含两个自定义函数一个(_selectedValuesContains)来检查相等性
列表中的对象,第二个(_selectedValuesRemove)在切换芯片时删除对象
Widget _buildChipSelectField(FormFieldState<dynamic> field) {
return Wrap(
spacing: 3.0,
children: _allValues.map((item) {
return FilterChip(
label: Text("${item['name']} - ${item['type']}"),
selectedColor: Colors.black38,
selected: _selectedValuesContains(item),
onSelected: (value) {
setState(() {
if (_selectedValuesContains(item)) {
_selectedValuesRemove(item);
} else {
_selectedValues.add(item);
}
field.didChange(_selectedValues);
});
},
);
}).toList(),
);
}
(这些方法适用于我的示例数据(即 _allValues),但这个想法本质上是非常基础的。)
_selectedValuesContains
bool _selectedValuesContains(Map item) {
int index = _selectedValues.indexWhere((val) => val['id'] == item['id']);
return index >= 0 ? true : false;
}
_selectedValuesRemove
void _selectedValuesRemove(Map item) {
int index = _selectedValues.indexWhere((val) => val['id'] == item['id']);
_selectedValues.removeAt(index);
}
我尝试将 FormBuilderFieldOption 的相同 'value' 字段的列表传递给 initialValue 参数。
编辑:通过列表满足 'required' 验证器但不会将筹码显示为 'marked'
现在,如果我没记错的话,这应该是 return 一组全部标记的筹码,但事实并非如此。
List<Map<String,dynamic>> _allValues = [
{id: 1586762938154, name: 202, rate: 5000, type: 'ABYSS'},
{id: 1586759232569, name: 101, rate: 1000, type: 'DELUXE'},
{id: 1586849439323, name: 13, rate: 3434, type: 'DELUXE'},
{id: 1586759258120, name: 102, rate: 2000, type: 'EXECUTIVE'},
{id: 1586779416843, name: 103, rate: 2343, type: 'EXECUTIVE'},
]
FormBuilderFilterChip(
initialValue: _allValues.map((value) => value).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map((val) => FormBuilderFieldOption(
value: val,
child: Text(val['name']),
),
).toList(),
onChanged: (value) {
_selected = value;
print(_selected);
},
)
您可以复制粘贴 运行 下面的完整代码
假设 _allValues
是 List<Map<String, String>>
代码片段
List<Map<String, String>> _allValues = [
{"name": "abc"},
{"name": "def"},
{"name": "123"}
];
FormBuilderFilterChip(
initialValue:
_allValues.map((value) => value['name']).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map(
(val) => FormBuilderFieldOption(
value: val['name'],
child: Text(val['name']),
),
)
.toList(),
工作演示
完整代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_form_builder/flutter_form_builder.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter FormBuilder Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
inputDecorationTheme: InputDecorationTheme(
labelStyle: TextStyle(color: Colors.purple),
),
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
MyHomePageState createState() {
return MyHomePageState();
}
}
class Data {
String name;
Data(this.name);
}
class MyHomePageState extends State<MyHomePage> {
var data;
bool autoValidate = true;
bool readOnly = false;
bool showSegmentedControl = true;
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
final GlobalKey<FormFieldState> _specifyTextFieldKey =
GlobalKey<FormFieldState>();
ValueChanged _onChanged = (val) => print(val);
var genderOptions = ['Male', 'Female', 'Other'];
List<Map<String, String>> _allValues = [
{"name": "abc"},
{"name": "def"},
{"name": "123"}
];
List<dynamic> _selected;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("FormBuilder Example"),
),
body: Padding(
padding: EdgeInsets.all(10),
child: SingleChildScrollView(
child: Column(children: <Widget>[
FormBuilder(
// context,
key: _fbKey,
autovalidate: true,
initialValue: {
'movie_rating': 5,
},
readOnly: false,
child: Column(
children: <Widget>[
FormBuilderFilterChip(
initialValue: ["Test 1", "Test 3"],
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: [
FormBuilderFieldOption(
value: 'Test', child: Text('Test')),
FormBuilderFieldOption(
value: 'Test 1', child: Text('Test 1')),
FormBuilderFieldOption(
value: 'Test 2', child: Text('Test 2')),
FormBuilderFieldOption(
value: 'Test 3', child: Text('Test 3')),
FormBuilderFieldOption(
value: 'Test 4', child: Text('Test 4')),
],
),
FormBuilderFilterChip(
initialValue:
_allValues.map((value) => value['name']).toList(),
attribute: 'filter_chip',
decoration: InputDecoration(
labelText: 'Select many options',
),
options: _allValues
.map(
(val) => FormBuilderFieldOption(
value: val['name'],
child: Text(val['name']),
),
)
.toList(),
onChanged: (value) {
_selected = value;
print(_selected);
},
)
],
),
),
]),
)));
}
}
我深入了解了 FormBuilderFilterChip 如何使用 List.contains()方法。
该方法中判断[element]是否等于List中某个元素的相等性默认为该元素的[Object.==]。
因此,为了解决这个问题,我构建了自己的自定义 FilterChipField(从 FormBuilderFilterChip 借用了大部分必要的代码)
FormBuilderCustomField(
attribute: "name",
validators: [
FormBuilderValidators.required(),
],
formField: FormField(
enabled: true,
builder: (FormFieldState<dynamic> field) {
return InputDecorator(
decoration: InputDecoration(
prefixIcon: Icon(Icons.vpn_key),
labelText: "Assign Room(s)",
contentPadding: EdgeInsets.only(top: 10.0, bottom: 0.0),
errorText: field.errorText,
),
child: Container(
child: _buildChipSelectField(field),
),
);
},
),
)
下面的_buildChipSelectField包含两个自定义函数一个(_selectedValuesContains)来检查相等性 列表中的对象,第二个(_selectedValuesRemove)在切换芯片时删除对象
Widget _buildChipSelectField(FormFieldState<dynamic> field) {
return Wrap(
spacing: 3.0,
children: _allValues.map((item) {
return FilterChip(
label: Text("${item['name']} - ${item['type']}"),
selectedColor: Colors.black38,
selected: _selectedValuesContains(item),
onSelected: (value) {
setState(() {
if (_selectedValuesContains(item)) {
_selectedValuesRemove(item);
} else {
_selectedValues.add(item);
}
field.didChange(_selectedValues);
});
},
);
}).toList(),
);
}
(这些方法适用于我的示例数据(即 _allValues),但这个想法本质上是非常基础的。)
_selectedValuesContains
bool _selectedValuesContains(Map item) {
int index = _selectedValues.indexWhere((val) => val['id'] == item['id']);
return index >= 0 ? true : false;
}
_selectedValuesRemove
void _selectedValuesRemove(Map item) {
int index = _selectedValues.indexWhere((val) => val['id'] == item['id']);
_selectedValues.removeAt(index);
}