如何在小部件方法中将变量作为状态传递?
How to pass variables as state in widget methods?
我有一段代码可以在 Flutter 中呈现 DropdownButton
。我需要几个下拉列表,所以我将它提取到一个方法中以调用我需要的每个实例。我在其中传递了所选值的状态变量,以及所有选项。在 DropdownButton 内部,我有在 DropdownButton
onChanged
方法中更新 selected
的方法。
因此,当我调用该方法而不是就地使用它时,问题就出现了,因为 onChanged 和 onClear 的函数不会重建小部件,因为它们不会更新调用之外的状态变量下拉方法。做这个的最好方式是什么?如果我从外部传入函数,它确实有效,但我将不得不复制一些代码。我应该将其重写为 StatefulWidget
吗?
DropdownButton myDropdown(
String selected,
List<dynamic> options, {
Function onChanged,
Function onClear,
}) {
return DropdownButton<String>(
value: selected,
// onChanged: (String newValue) { // Not working
// setState(() {
// selected = newValue;
// });
// },
onChanged: onChanged,
selectedItemBuilder: (BuildContext context) {
return options?.map<Widget>((dynamic item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(item),
IconButton(
icon: Icon(Icons.clear),
// onPressed: () { // Not working
// setState(() {
// selected = null;
// });
// },
onPressed: onClear,
),
],
);
})?.toList() ?? [];
},
items: options?.map<DropdownMenuItem<String>>((dynamic value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
})?.toList() ?? [],
);
}
(在项目中我确实使用了provider来进行状态管理,但我不确定它是否真的与这个问题相关。)
在您调用 DropdownButton
的父级 class 的某处定义 selected
var selected;
现在这样写DropdownButton -
DropdownButton(
selected,
[whatever],
onChanged: (newValue) {
selected = newValue;
setState(() {});
}
onClear: () {
selected = null;
setState(() {});
}
)
因此,一旦调用 onChanged 或 onClear,它就会更改 selected
值并使用新选择的值刷新小部件。
解决方案是通过将 DropdownButton
的值包装在 StatefulWidget
中来管理它的状态。
我已经提供了一个自定义示例 Widget
来实现此目的,本着与您的原始代码相同的精神。
import 'package:flutter/material.dart';
/// A managed [DropdownButton] initialized to [selected] with possible values
/// [options].
///
/// Selected value is updated on dropdown item clicks, and triggers [onChanged]
/// callback.
///
/// An "x" clear button is present on all menu items, and sets selected item to
/// null, while also triggering [onClear] callback.
class SuperDropdown extends StatefulWidget {
SuperDropdown({
@required this.selected,
@required this.options,
this.onClear,
this.onChanged,
});
final Function(String s) onChanged;
final Function() onClear;
final List<String> options;
final String selected;
@override
_SuperDropdownState createState() => _SuperDropdownState();
}
class _SuperDropdownState extends State<SuperDropdown> {
String selected;
List<DropdownMenuItem> get items => widget.options
.map((i) => DropdownMenuItem(
value: i,
child: Text(i),
))
.toList();
void onChanged(String value) {
setState(() => selected = value);
widget.onChanged?.call(value);
}
void onClear() {
setState(() => selected = null);
widget.onClear?.call();
}
List<Widget> itemBuilder(BuildContext context) => widget.options
.map((i) =>
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(i),
IconButton(
icon: Icon(Icons.clear),
onPressed: onClear,
),
]))
.toList();
@override
void initState() {
super.initState();
selected = widget.selected;
}
@override
Widget build(BuildContext context) => DropdownButton<String>(
value: selected,
items: items,
onChanged: onChanged,
selectedItemBuilder: itemBuilder,
);
}
void main() => runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: ["abc", "def"]
.map((letters) => SuperDropdown(
selected: letters.substring(0, 1),
options: letters.split(''),
onChanged: (s) =>
print("dropdown $letters changed to $s"),
onClear: () => print("dropdown $letters cleared"),
))
.toList(),
),
),
),
),
);
我有一段代码可以在 Flutter 中呈现 DropdownButton
。我需要几个下拉列表,所以我将它提取到一个方法中以调用我需要的每个实例。我在其中传递了所选值的状态变量,以及所有选项。在 DropdownButton 内部,我有在 DropdownButton
onChanged
方法中更新 selected
的方法。
因此,当我调用该方法而不是就地使用它时,问题就出现了,因为 onChanged 和 onClear 的函数不会重建小部件,因为它们不会更新调用之外的状态变量下拉方法。做这个的最好方式是什么?如果我从外部传入函数,它确实有效,但我将不得不复制一些代码。我应该将其重写为 StatefulWidget
吗?
DropdownButton myDropdown(
String selected,
List<dynamic> options, {
Function onChanged,
Function onClear,
}) {
return DropdownButton<String>(
value: selected,
// onChanged: (String newValue) { // Not working
// setState(() {
// selected = newValue;
// });
// },
onChanged: onChanged,
selectedItemBuilder: (BuildContext context) {
return options?.map<Widget>((dynamic item) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(item),
IconButton(
icon: Icon(Icons.clear),
// onPressed: () { // Not working
// setState(() {
// selected = null;
// });
// },
onPressed: onClear,
),
],
);
})?.toList() ?? [];
},
items: options?.map<DropdownMenuItem<String>>((dynamic value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
})?.toList() ?? [],
);
}
(在项目中我确实使用了provider来进行状态管理,但我不确定它是否真的与这个问题相关。)
在您调用 DropdownButton
的父级 class 的某处定义selected
var selected;
现在这样写DropdownButton -
DropdownButton(
selected,
[whatever],
onChanged: (newValue) {
selected = newValue;
setState(() {});
}
onClear: () {
selected = null;
setState(() {});
}
)
因此,一旦调用 onChanged 或 onClear,它就会更改 selected
值并使用新选择的值刷新小部件。
解决方案是通过将 DropdownButton
的值包装在 StatefulWidget
中来管理它的状态。
我已经提供了一个自定义示例 Widget
来实现此目的,本着与您的原始代码相同的精神。
import 'package:flutter/material.dart';
/// A managed [DropdownButton] initialized to [selected] with possible values
/// [options].
///
/// Selected value is updated on dropdown item clicks, and triggers [onChanged]
/// callback.
///
/// An "x" clear button is present on all menu items, and sets selected item to
/// null, while also triggering [onClear] callback.
class SuperDropdown extends StatefulWidget {
SuperDropdown({
@required this.selected,
@required this.options,
this.onClear,
this.onChanged,
});
final Function(String s) onChanged;
final Function() onClear;
final List<String> options;
final String selected;
@override
_SuperDropdownState createState() => _SuperDropdownState();
}
class _SuperDropdownState extends State<SuperDropdown> {
String selected;
List<DropdownMenuItem> get items => widget.options
.map((i) => DropdownMenuItem(
value: i,
child: Text(i),
))
.toList();
void onChanged(String value) {
setState(() => selected = value);
widget.onChanged?.call(value);
}
void onClear() {
setState(() => selected = null);
widget.onClear?.call();
}
List<Widget> itemBuilder(BuildContext context) => widget.options
.map((i) =>
Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(i),
IconButton(
icon: Icon(Icons.clear),
onPressed: onClear,
),
]))
.toList();
@override
void initState() {
super.initState();
selected = widget.selected;
}
@override
Widget build(BuildContext context) => DropdownButton<String>(
value: selected,
items: items,
onChanged: onChanged,
selectedItemBuilder: itemBuilder,
);
}
void main() => runApp(
MaterialApp(
home: Scaffold(
body: Center(
child: Column(
children: ["abc", "def"]
.map((letters) => SuperDropdown(
selected: letters.substring(0, 1),
options: letters.split(''),
onChanged: (s) =>
print("dropdown $letters changed to $s"),
onClear: () => print("dropdown $letters cleared"),
))
.toList(),
),
),
),
),
);