首先,这是我的病情。我试图将第一个屏幕(左图)的Dropdownbutton和Date&Time选择器中填充的所有数据传递到第二个屏幕(右图)。问题是,我将DropDownButton小部件提取到另一个类,但我不知道如何实现它。
在此之前,这是第一个屏幕代码:
"cleanUrls": true,
"trailingSlash": false,
在第一张图片下方,有一个按钮导航到第二张屏幕。
这是我提取DropDownButton的类:
class InformationDetail extends StatefulWidget {
static const String id = 'InformationDetail';
@override
_InformationDetailState createState() => _InformationDetailState();
}
class _InformationDetailState extends State<InformationDetail> {
String addressText, addNotes;
DateTime selectedDate = DateTime.now();
TimeOfDay selectedTime = TimeOfDay.now();
Future<Null> _selectDate(BuildContext context) async {
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101));
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
});
}
Future<Null> _selectTime(BuildContext context) async {
final TimeOfDay picked = await showTimePicker(
context: context,
initialTime: selectedTime,
);
if (picked != null && picked != selectedTime)
setState(() {
selectedTime = picked;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
Container(
margin: EdgeInsets.fromLTRB(25.0, 68.0, 70.0, 26.0),
child: Text(
'Information Detail',
style: TextStyle(fontSize: 35.0),
),
),
Column(
// Wrap Column
children: <Widget>[
Column(
children: <Widget>[
TitleName(
titleText: 'Grooming Type',
infoIcon: Icons.info,
),
MenuDropDown(
dropdownText: 'Grooming Type...',
type: "groomingType",
),
TitleName(
titleText: 'Cat Breeds',
),
MenuDropDown(
dropdownText: 'Cat Breeds...',
type: "catBreeds",
),
TitleName(
titleText: 'Cat Size',
infoIcon: Icons.info,
),
MenuDropDown(
dropdownText: 'Cat Size...',
type: "catSize",
),
TitleName(
titleText: 'Add-On Services',
),
MenuDropDown(
dropdownText: 'Add - On Services...',
type: "addOnServices",
),
TitleName(
titleText: 'Reservation Date',
),
Row(
children: <Widget>[
Container(
width: 130,
height: 30,
margin: EdgeInsets.fromLTRB(50.0, 0, 62, 0),
child: RaisedButton(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 6,
child: Text(
'Choose Date',
style: TextStyle(
fontSize: 12.0,
),
),
onPressed: () => _selectDate(context),
),
),
Text("${selectedDate.toLocal()}".split(' ')[0]),
],
),
TitleName(
titleText: 'Reservation Time',
),
Row(
children: <Widget>[
Container(
width: 130,
height: 30,
margin: EdgeInsets.fromLTRB(50.0, 0, 62, 0),
decoration: BoxDecoration(),
child: RaisedButton(
color: Colors.white,
child: Text(
'Choose Time',
style: TextStyle(
fontSize: 12.0,
),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
elevation: 6,
onPressed: () => _selectTime(context),
),
),
Text("${selectedTime.toString()}".split(' ')[0]),
],
),
TitleName(
titleText: 'Pick Up Address',
),
Container(
width: 320,
height: 40,
child: TextFormField(
maxLines: null,
minLines: null,
expands: true,
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(35.0, 10.0, 0, 10.0),
hintText: 'Address Here...',
hintStyle: TextStyle(
fontSize: 15.0,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
onChanged: (value) {
addressText = value;
},
),
),
TitleName(
titleText: 'Additional Notes',
infoIcon: Icons.info,
),
Container(
width: 320,
child: TextFormField(
maxLines: 4,
decoration: InputDecoration(
contentPadding:
EdgeInsets.fromLTRB(35.0, 10.0, 0, 10.0),
hintText: 'E.g. ',
hintStyle: TextStyle(
fontSize: 15.0,
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15.0),
),
),
onChanged: (value) {
addNotes = value;
},
),
),
Container(
margin: EdgeInsets.fromLTRB(0, 15.0, 0, 0),
width: 75.0,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.rectangle,
border: Border.all(
color: Colors.black,
),
borderRadius: BorderRadius.circular(12.0),
),
child: IconButton(
icon: Icon(Icons.arrow_forward),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => ConfirmationOrder(
addressText: addressText,
addNotes: addNotes,
)));
}),
),
],
),
],
),
],
),
),
],
)),
);
}
}
我真的很困惑,因为DropDownButton中的onChanged函数已经被使用了。我几乎无法从文本窗口小部件中进行正常的传递数据。但是从下拉菜单和日期和时间选择器中,我不知道该怎么做。
有什么方法可以从第一个屏幕上获取数据,因为目前我还没有了解状态管理或Bloc。而且代码仍然凌乱,我还没有完成重构。我真的希望您能提供解决方案,谢谢!
答案 0 :(得分:1)
首先,对于MenuDropDown
,您将需要对onChanged
方法进行某种扩展。像这样向小部件的构造函数添加一个VoidCallback
参数:
typedef OnChangeCallback = void Function(dynamic value);
class MenuDropDown extends StatefulWidget {
final String dropdownText;
final String type;
final OnChangeCallback onChanged;
MenuDropDown({this.dropdownText, this.type, this.onChanged});
@override
_MenuDropDownState createState() => _MenuDropDownState();
}
并在状态下,将该方法作为DropdownButton
的本机onChanged
回调的一部分进行调用:
onChanged: (value) {
setState(() {
selectedItem = value;
});
widget.onChanged(value);
}
在_InformationDetailState
中,您将为每个输入字段存储当前选定的项目,并传递一个onChanged
函数,该函数将为每个输入更新相应的字段:
String catSize; //Declare at the top of _InformationDetailState
...
MenuDropDown(
dropdownText: 'Cat Size...',
type: "catSize",
onChanged: (value) {
catSize = value;
}
),
现在将数据传递到下一个屏幕。在您的应用程序中使用任何一种状态管理从来都不是绝对必要的,而且我发现很多人不必要地使用它。在您的情况下,仅将数据传递到其他单个小部件绝对没有必要。您已经正确传递了addressText
和addNotes
。只需将其扩展为您需要在确认屏幕上显示的每个参数即可。或者,您可以将所有字段存储在单个Map
中,而不是每个字段都有一个变量,然后将该Map
传递到确认页面。