从 Flutter 中的 Stateful Widget 返回数据
Posted
技术标签:
【中文标题】从 Flutter 中的 Stateful Widget 返回数据【英文标题】:Returning data from a Stateful Widget in Flutter 【发布时间】:2019-07-08 16:51:10 【问题描述】:我之前已经发布过我仍然面临的这个问题 也就是将数据从有状态小部件返回到无状态小部件
我使用的小部件是 DateTimePickerFormField 小部件,我在有状态小部件中将它用作子部件
所以我看过https://flutter.io/docs/cookbook/navigation/returning-data#complete-example
用于从小部件返回数据。但是,返回数据的小部件是无状态小部件......在我的情况下不是
所以代码如下
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text('Add a Reminder'),
),
body:
new Container(
padding: new EdgeInsets.all(20.0),
child: new Form(
child: new ListView(
children: <Widget>[
new TextFormField(
keyboardType: TextInputType.text,
// Use email input type for emails.
decoration: new InputDecoration(
hintText: 'Title of reminder',
),
),
dateAndTimeWidget(context),
RaisedButton(
child: Text('Save'),
onPressed: ()
Navigator.pop(context);
,
)
],
),)
,
)
,
);
那个小部件正在调用方法:dateAndTimeWidget,它应该返回 dateTime 有状态小部件并将输出的数据保存在一个变量中:
dateAndTimeWidget(BuildContext context) async
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context)=> dateTime()),
);
那么这是 dateTime Statful 小部件
class dateTime extends StatefulWidget
@override
dateTimeState createState() => dateTimeState();
class dateTimeState extends State<dateTime>
static DateTime dateT;
InputType inputType = InputType.both;
final formats =
InputType.both: DateFormat("EEEE, MMMM d, yyyy 'at' h:mma"),
InputType.date: DateFormat('yyyy-MM-dd'),
InputType.time: DateFormat("HH:mm"),
;
Widget build(BuildContext context) => Container(
child: DateTimePickerFormField(
inputType: InputType.both,
editable: true,
format: formats[inputType],
decoration: InputDecoration(
labelText: 'Date/Time', hasFloatingPlaceholder: false),
onChanged: (dt)
setState(() => dateT = dt);
Navigator.of(context).pop(dateT);
,
)
);
我还没有使用值结果 因为错误是我从来没有进入添加提醒页面,它说结果推送导航方法指向 null
【问题讨论】:
【参考方案1】:在这种情况下,使用 Navigator 传递数据是不合适的。因为页面和您的dateTime
Widget 之间没有页面转换。我建议您实现ValueChanged
回调以在同一屏幕的小部件之间传递数据。
示例代码:
这有点棘手。但是material.dart
的小部件经常使用这种技术。我希望这能帮到您!
class MyHomePage extends StatefulWidget
@override
_MyHomePageState createState() => _MyHomePageState();
class _MyHomePageState extends State<MyHomePage>
DateTime dateT;
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text('Add a Reminder'),
),
body: new Container(
padding: new EdgeInsets.all(20.0),
child: new Form(
child: new ListView(
children: <Widget>[
new TextFormField(
keyboardType: TextInputType.text,
// Use email input type for emails.
decoration: new InputDecoration(
hintText: 'Title of reminder',
),
),
dateTime(
onDateTimeChanged: (newDateTime)
dateT = newDateTime;
,
),
RaisedButton(
child: Text('Save'),
onPressed: ()
Navigator.pop(context);
,
)
],
),
),
),
);
class dateTime extends StatefulWidget
final ValueChanged<DateTime> onDateTimeChanged;
dateTime(Key key, this.onDateTimeChanged) : super(key: key);
@override
dateTimeState createState() => dateTimeState();
class dateTimeState extends State<dateTime>
DateTime dateT;
InputType inputType = InputType.both;
final formats =
InputType.both: DateFormat("EEEE, MMMM d, yyyy 'at' h:mma"),
InputType.date: DateFormat('yyyy-MM-dd'),
InputType.time: DateFormat("HH:mm"),
;
Widget build(BuildContext context) => Container(
child: DateTimePickerFormField(
inputType: InputType.both,
editable: true,
format: formats[inputType],
decoration: InputDecoration(
labelText: 'Date/Time', hasFloatingPlaceholder: false),
onChanged: (dt)
widget.onDateTimeChanged(dt);
,
),
);
(顺便说一句,你的dateAndTimeWidget
是一个方法,不是一个小部件。所以如果你将它分配给 Column 的子项(列表),Flutter 框架无法理解。)
【讨论】:
【参考方案2】:对于从另一个小部件返回值并使用它的更节省时间的解决方案,这是 Flutter Dropdown 的示例:
import 'package:flutter/material.dart';
import 'package:paxi_ride/constant.dart';
class BuildDropdown extends StatefulWidget
final ValueChanged<String> onChanged;
String defaultValue, selectedValue, dropdownHint;
List<String> itemsList;
BuildDropdown(
Key key,
this.itemsList,
this.defaultValue,
this.dropdownHint,
this.onChanged)
: super(key: key);
@override
_BuildDropdownState createState() => _BuildDropdownState();
class _BuildDropdownState extends State<BuildDropdown>
String _value;
@override
Widget build(BuildContext context)
return Container(
// height: 40,
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 0),
margin: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
color: Colors.white,
child: DropdownButton<String>(
items: widget.itemsList.map(
(String value)
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
,
).toList(),
value: _value == null ? widget.defaultValue : _value,
isExpanded: true,
onChanged: (String value)
setState(()
_value = value;
);
widget.onChanged(value);
,
hint: Text(widget.dropdownHint),
style: TextStyle(
fontSize: 14,
color: brownColorApp,
),
iconEnabledColor: brownColorApp,
iconSize: 14,
underline: Container(),
),
);
从另一个小部件调用此小部件,您希望在其中获取选定值,如下所示:
String selectedValue; //class field
BuildDropdown(
itemsList: ['Option 1','Option 2'],
defaultValue: 'Option 1',
dropdownHint: 'Select Required Option',
onChanged: (value)
selectedValue = value;
,
),
在需要的地方使用这个值,它会随着下拉选择的改变而改变。
【讨论】:
以上是关于从 Flutter 中的 Stateful Widget 返回数据的主要内容,如果未能解决你的问题,请参考以下文章
Flutter Stateful Widget 状态未初始化
Flutter: Stateful 挂件 vs Stateless 挂件
Flutter控件篇(Stateful widget)——ListView
Flutter - Stateful(有状态) 和 stateless(无状态) widgets