在DropdownButtonFormField
中,我有一个从Provider填充的标准DropdownMenuItems
列表;添加新的";按钮,该按钮按下包含CCD_ 4的CCD_。提交后,表单通过Provider
将新数据异步插入数据库,并在对Navigator.pop()
的调用中返回数据库id。
预期的行为是,pop((回调应该将下拉字段的值设置为返回的int值,并且应该关闭下拉菜单,并反映更新后的值。
在下面的代码片段中,我有两个版本的";添加新的";DropdownMenuItem
。";工作";该版本的运行与预期的一样,但按下时不会关闭下拉菜单(也与预期一样,因为它是一个按钮,而不是一个正常的下拉元素(。
";破碎的";版本无法推送新路线,并抛出
E/flutter (24895): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type '_DropdownRouteResult<int>' is not a subtype of type 'int?'
E/flutter (24895): #0 _TeaProducerFormFieldState.build.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:teavault/screens/stash/teaform.dart:70:15)
E/flutter (24895): #1 State.setState (package:flutter/src/widgets/framework.dart:1109:30)
E/flutter (24895): #2 _TeaProducerFormFieldState.build.<anonymous closure>.<anonymous closure> (package:teavault/screens/stash/teaform.dart:69:13)
E/flutter (24895): #3 _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter (24895): #4 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
这里所指的L70是CCD_ 8。无论我使用async/await还是.then((语法,都会发生这种行为。
我不知道这是由于先发制人的类型检查,还是由于我遗漏了一些东西而导致等待Promise的奇怪失败。
相关代码如下:
class _TeaProducerFormFieldState extends State<TeaProducerFormField> {
int? _selectedValue;
@override
Widget build(BuildContext context) {
final teaProducers = Provider.of<TeaProducerCollectionModel>(context).items;
final teaProducerListItems = teaProducers.map((producer) => DropdownMenuItem<int>(
value: producer.id,
child: Text(producer.name),
)).toList();
final workingAddNewTeaProducerButton = DropdownMenuItem<int>(child: TextButton(
onPressed: () async {
final int newValue = await Navigator.push(context, AddNewTeaProducerRoute());
setState(() {
_selectedValue = newValue;
});
},
child: Text('Add New Manufacturer')));
final brokenAddNewTeaProducerButtion = DropdownMenuItem<int>(
onTap: () {
Navigator.push(context, AddNewTeaProducerRoute()).then((value) {
setState(() {
_selectedValue = value;
});
});
},
value: 0,
child: const Text('Add New Manufacturer'));
return DropdownButtonFormField(
value: _selectedValue,
items: teaProducerListItems + [brokenAddNewTeaProducerButtion],
// child: addNewTeaProducerButton)],
onChanged: (_) {},
hint: Text('Select a manufacturer'),
);
}
}
编辑:根据@Axel的建议进行修改并直接拉入子树内容以保持清晰后,我有以下内容,但仍然收到
When the exception was thrown, this was the stack:
#0 LocalHistoryRoute.didPop (package:flutter/src/widgets/routes.dart)
#1 _RouteEntry.handlePop (package:flutter/src/widgets/navigator.dart:2896:16)
#2 NavigatorState._flushHistoryUpdates (package:flutter/src/widgets/navigator.dart:3868:22)
#3 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:4910:7)
#4 Navigator.pop (package:flutter/src/widgets/navigator.dart:2432:27)
#5 _DropdownMenuItemButtonState._handleOnTap (package:flutter/src/material/dropdown.dart:148:15)
我想在相关的MaterialPageRoute中添加一个int?
类型的arg,但收到了相同的结果。
final brokenAddNewTeaProducerButton = DropdownMenuItem<int>(
onTap: () {
Navigator.push<int?>(context, MaterialPageRoute(
builder: (BuildContext context) =>
Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.white),
title: Text('Define new Manufacturer'),
),
body: Column(
children: <Widget>[
Expanded(
flex: MediaQuery.of(context).orientation == Orientation.portrait ? 4 : 1,
child: Container(),
),
Expanded(
flex: 16,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 50.0),
child: const TeaProducerForm(),
),
),
],
)
))).then((value) {
setState(() {
_selectedValue = value;
});
});
},
value: 0,
child: const Text('Add New Manufacturer'));
//[...]
class TeaProducerFormState extends State<TeaProducerForm> {
final _formKey = GlobalKey<FormState>();
String? fullName;
String? shortName;
@override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
children: <Widget>[
TextFormField(
onSaved: ((value) {fullName = value;}),
decoration: const InputDecoration(
hintText: 'Enter full name',
labelText: 'Full Name'
),
),
TextFormField(
onSaved: ((value) {shortName = value;}),
decoration: const InputDecoration(
hintText: 'Enter abbreviated name',
labelText: 'Short Name'
),
validator: ((value) {
if ((value ?? '').length > 6 ) {
return 'Please enter a name with six or fewer characters';
} else if ((value ?? '').isEmpty ) {
return 'Please enter a name with one or more characters';
}
}),
),
ElevatedButton(
onPressed: () async {
if (_formKey.currentState?.validate() ?? false) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Saving new manufacturer...')),);
_formKey.currentState?.save();
final teaProducers = Provider.of<TeaProducerCollectionModel>(context, listen: false);
teaProducers.insert(TeaProducer(
name: fullName!,
shortName: shortName!
)).then((value) {
print('added tea as id $value');
ScaffoldMessenger.of(context).clearSnackBars();
Navigator.pop<int?>(context, value);
});
}
},
child: const Text('Submit'))
// Add TextFormFields and ElevatedButton here.
],
),
);
}
}
尝试指定期望从Navigator.push
返回的类型,以及在AddNewTeaProducerRoute中Navigator.pop
时要返回的类型。
你的代码应该看起来像:
final brokenAddNewTeaProducerButtion = DropdownMenuItem<int>(
onTap: () {
Navigator.push<int?>(context, AddNewTeaProducerRoute()).then((value) {
setState(() {
_selectedValue = value;
});
});
},
value: 0,
child: const Text('Add New Manufacturer'));
在AddNewTeaProducerRoute内部,执行:
Navigator.pop<int?>(context, value);
在此之后,您不应该得到任何强制转换异常。