问题
I have previously posted about this problem I am still facing Which is to return data from a Stateful widget back to a Stateless Widget
The Widget I am using is DateTimePickerFormField widget and I am using it as a child in a stateful widget
So I have looked at https://flutter.io/docs/cookbook/navigation/returning-data#complete-example
For returning data from a widget. However, the widget that is returning the data is a stateless widget ...Which in my case isn't
So The code goes as follows
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);
},
)
],
),)
,
)
,
);
}
That Widget is calling the method: dateAndTimeWidget, Which is supposed to return the dateTime stateful widget and save the outcoming data in a variable :
dateAndTimeWidget(BuildContext context) async {
final result = await Navigator.push(
context,
MaterialPageRoute(builder: (context)=> dateTime()),
);
}
Then This is the dateTime Statful widget
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);
},
)
);
}
I am not using the value result yet Because the error is that I never get to the add reminder page and it says that the result push navigation method is pointing at null
回答1:
In this situation passing data with Navigator is not suitable. Because there isn't page transition between the page and your dateTime
Widget. I recommend you to implement ValueChanged
callback to pass data between widgets in same screen.
example code:
It's little bit tricky. But material.dart
's widgets often use this technique. I hope this will help you!
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);
},
),
);
}
(Btw your dateAndTimeWidget
is a method, is not a Widget. So if you assign it to Column`s children(List), Flutter framework cannot understand.)
回答2:
For more time saving solution for returning value from another widget and using it, here's an example for 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(),
),
);
}
}
Call this widget from another widget where you want to get selected value like this:
String selectedValue; //class field
BuildDropdown(
itemsList: ['Option 1','Option 2'],
defaultValue: 'Option 1',
dropdownHint: 'Select Required Option',
onChanged: (value) {
selectedValue = value;
},
),
Use this value wherever needed, it will be changed as dropdown selection is changed.
来源:https://stackoverflow.com/questions/54694169/returning-data-from-a-stateful-widget-in-flutter