[英]How to build dependent dropdown menus in Flutter?
我有三个下拉菜单,我希望ONLY
在满足某些条件ONLY
显示第四个( Favourite Animal = Cat
)。 我还希望当条件不再成立时,第四个下拉菜单消失。 现在,如果我手动保存文件并执行热重载,就会显示更改,所以我猜它与setState()
,我没有包含在filter.dart
文件中。
文件 1 - filter.dart:
import 'package:flutter/material.dart';
import './dropdown.dart';
class Filter extends StatefulWidget {
@override
_FilterState createState() => _FilterState();
}
class _FilterState extends State<Filter> {
@override
Widget build(BuildContext context) {
return Card(
elevation: 10,
child: Container(
height: ((MediaQuery.of(context).size.height) / 2),
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
children: <Widget>[
Dropdown('Gender', ['Female', 'Male']),
Dropdown('Age', ['<15', '15-20', '>20']),
Dropdown('Favourite Animal', ['Cat', 'Dog', 'Hamster']),
(cat) ? Dropdown('Favourite cat-toy', ['Toy-mouse', 'Ribbon', 'Ball']) : Text('')
],
),
RaisedButton(
child: Text('Submit'),
onPressed: () {},
),
],
),
),
);
}
}
文件 2 - dropdown.dart:
import 'package:flutter/material.dart';
class Dropdown extends StatefulWidget {
final String _key;
final List<String> _values;
Dropdown(this._key, this._values);
@override
_DropdownState createState() => _DropdownState();
}
class _DropdownState extends State<Dropdown> {
var _chosenValue;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: DropdownButton<String> (
hint: Text(widget._key),
value: _chosenValue,
icon: Icon(Icons.arrow_drop_down),
iconSize: 24,
isExpanded: true,
items: widget._values.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String value) {
_chosenValue = value;
(widget._key == 'Favourite Animal' && _chosenValue == 'Cat') ? cat = true : cat = false;
setState(() {
});
},
),
);
}
}
bool cat = false; //Feels wrong to have this bool out in the open
filter.dart
文件从 main 调用Filter()
。
奖金的问题:我也想提取所选择的值,并将其返回filter.dart
-file,并利用它们在onPressed
在-function RaisedButton
,不太清楚该怎么做。
在DropdownButton
有onChanged
回调:
onChanged: (String value) {
_chosenValue = value;
(widget._key == 'Favourite Animal' && _chosenValue == 'Cat') ? cat = true : cat = false;
setState(() {
});
}
对setState()
调用将用于 Dropdown 小部件,而不是更高的 Filter 小部件。
解决此问题的一种方法是向您的自定义 Dropdown 类添加函数回调:
class Dropdown extends StatefulWidget {
final String _key;
final List<String> _values;
final Function callback;
Dropdown(this._key, this._values, this.callback);
@override
_DropdownState createState() => _DropdownState();
}
并且,在 onChanged 属性中:
onChanged: (String value) {
_chosenValue = value;
(widget._key == 'Favourite Animal' && _chosenValue == 'Cat') ? cat = true : cat = false;
callback();
},
这将调用您在创建 Dropdown 时定义的回调:
children: <Widget>[
Dropdown('Gender', ['Female', 'Male'], callbackFunc),
Dropdown('Age', ['<15', '15-20', '>20'], callbackFunc),
Dropdown('Favourite Animal', ['Cat', 'Dog', 'Hamster'], callbackFunc),
(cat) ? Dropdown('Favourite cat-toy', ['Toy-mouse', 'Ribbon', 'Ball'], callbackFunc) : Text('')
],
callbackFunc 可能很简单:
void callbackFunc(){
setState((){});
}
当然,这不是最优雅的解决方案。 由于您正在使用回调,您可以撤消您使用的所有全局变量,只需使用带有参数的回调:
void callbackFunc(String value){
if (value=='cat')
choseCat=true;
else
choseCat=false;
setState((){});
}
此外,您不必检查小部件键来验证正在调用哪个下拉列表。 可以在调用前检查回调是否为空,只给合适的回调函数:
children: <Widget>[
Dropdown('Gender', ['Female', 'Male']),
Dropdown('Age', ['<15', '15-20', '>20']),
Dropdown('Favourite Animal', ['Cat', 'Dog', 'Hamster'], callbackFunc),
(cat) ? Dropdown('Favourite cat-toy', ['Toy-mouse', 'Ribbon', 'Ball']) : Text('')
],
[...]
onChanged: (String value) {
_chosenValue = value;
(widget._key == 'Favourite Animal' && _chosenValue == 'Cat') ? cat = true : cat = false;
if (callback)
callback();
},
在这种情况下,不要忘记将回调设为可选:
Dropdown({@required this._key, @required this._values, this.callback});
我确信可以用这种方法完成许多其他优化。 对于更大的应用程序,应该选择其他状态管理方法,让您的生活更轻松。
修复 6 个位置。 这个怎么样?
class _FilterState extends State<Filter> {
bool cat = false; // Move here.
@override
Widget build(BuildContext context) {
return Card(
elevation: 10,
child: Container(
height: ((MediaQuery.of(context).size.height) / 2),
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
children: <Widget>[
Dropdown('Gender', ['Female', 'Male']),
Dropdown('Age', ['<15', '15-20', '>20']),
Dropdown('Favourite Animal', ['Cat', 'Dog', 'Hamster'], update: _update), // Fix this line.
(cat)
? Dropdown(
'Favourite cat-toy', ['Toy-mouse', 'Ribbon', 'Ball'])
: Text('')
],
),
RaisedButton(
child: Text('Submit'),
onPressed: () {},
),
],
),
),
);
}
// Add this function.
void _update(bool b) {
setState(() {
cat = b;
});
}
}
class Dropdown extends StatefulWidget {
final String _key;
final List<String> _values;
final Function update; // Add this line.
Dropdown(this._key, this._values, {this.update = null}); // Fix this line.
@override
_DropdownState createState() => _DropdownState();
}
class _DropdownState extends State<Dropdown> {
var _chosenValue;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 5),
child: DropdownButton<String>(
hint: Text(widget._key),
value: _chosenValue,
icon: Icon(Icons.arrow_drop_down),
iconSize: 24,
isExpanded: true,
items: widget._values.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String value) {
// Fix start.
setState(() {
_chosenValue = value;
});
if (widget.update != null) {
(widget._key == 'Favourite Animal' && _chosenValue == 'Cat')
? widget.update(true)
: widget.update(false);
}
// Fix end.
},
),
);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.