如何从DropdownMenuItem的onTap调用Navigator.push()并等待返回值?
我通过Provider从数据库动态填充DropdownFormField,需要添加一个DropdownMenuItem:选中该选项时跳转到新路由插入数据库记录,返回时把新插入记录的ID设为下拉框的选中值。尝试了两种方案,遇到了类型转换异常问题:
方案一:TextButton作为子组件
- 效果:跳转和返回逻辑正常,返回后下拉框选中值能正确更新,但样式和普通菜单项不一致,点击按钮不会自动关闭下拉菜单,需点击外部才会收起。
- 代码示例:
DropdownMenuItem<int>( child: TextButton( onPressed: () async { final int newValue = await Navigator.push(context, AddNewTeaProducerRoute()); setState(() { _selectedValue = newValue; }); }, child: Text('Add New Manufacturer') ) );
方案二:Text作为子组件(触发异常)
- 问题:在DropdownMenuItem的
onTap中写异步跳转逻辑,会直接抛出异常Unhandled Exception: type '_DropdownRouteResult<int>' is not a subtype of type 'int?'。调试发现,newValue会被立即赋值为Future/_DropdownRouteResult<int>,而非等待路由返回的int类型。 - 代码示例:
DropdownMenuItem<int>( onTap: () async { final int newValue = await Navigator.push(context, AddNewTeaProducerRoute()); setState(() { _selectedValue = newValue; }); }, child: const Text('Add New Manufacturer') );
原因分析
DropdownMenuItem的onTap并非为异步操作设计:点击该选项时,下拉路由(DropdownRoute)会自动尝试将当前item的value返回给DropdownFormField。而我们的异步Navigator.push还未完成,此时下拉路由返回的_DropdownRouteResult<int>类型,和DropdownFormField期望的int?类型不匹配,从而触发类型转换异常。而TextButton的onPressed不会触发DropdownMenuItem的默认选中逻辑,因此不会产生冲突。
可行解决办法
方法1:设置空value并手动关闭下拉菜单
将DropdownMenuItem的value设为null,避免下拉路由返回无效值;在onTap中先关闭下拉菜单,再执行跳转逻辑:
DropdownMenuItem<int>( value: null, onTap: () async { // 先关闭下拉菜单 Navigator.pop(context); // 跳转路由并等待返回ID final int? newValue = await Navigator.push(context, AddNewTeaProducerRoute()); if (newValue != null) { setState(() { _selectedValue = newValue; }); } }, child: const Text('Add New Manufacturer') );
方法2:用InkWell包裹子组件保留样式
禁用DropdownMenuItem的默认点击逻辑,用InkWell包裹子元素处理点击,既保留菜单项的原生样式,又能正常执行异步操作:
DropdownMenuItem<int>( enabled: false, child: InkWell( onTap: () async { Navigator.pop(context); final int? newValue = await Navigator.push(context, AddNewTeaProducerRoute()); if (newValue != null) { setState(() { _selectedValue = newValue; }); } }, child: const Text('Add New Manufacturer'), ), );
内容的提问来源于stack exchange,提问作者A Dunn
相关产品推荐
相关产品推荐

