Flutter连续弹窗时大尺寸二次弹窗出现短暂RenderFlex溢出问题
问题描述
点击按钮后会依次弹出两个Alert Dialog:
- 当第二个弹窗的垂直尺寸大于第一个时,会短暂出现
FLT: A RenderFlex overflowed by 46 pixels on the bottom.的错误提示,随后瞬间消失; - 若第二个弹窗尺寸更小则无此问题。
已确认第一个弹窗弹出逻辑正确,且父Widget的TextEditingController已正确清理,但无法理解为何出现这个短暂溢出错误,其他功能均正常,在Android模拟器和调试控制台中都能看到该错误。想确认这是Flutter的bug还是自身实现问题。
相关代码如下:
class _ParentWidgetState extends State<ParentWidget> { late TextEditingController controller; // init, dispose, build 等其他代码... }
ElevatedButton( // 其他属性... onPressed: () async { someText = await firstDialog(); await secondDialog(someText); } )
Future<String?> firstDialog() { return showDialog<String>( context: context, builder: (context) => AlertDialog( title: const Text('Enter something'), content: TextField( decoration: const InputDecoration( hintText: 'Enter something'), autofocus: true, controller: controller, onSubmitted: (_) { Navigator.of(context).pop(controller.text); controller.clear(); }), actions: [ TextButton( onPressed: () { Navigator.of(context).pop(controller.text); controller.clear(); }, child: const Text('SUBMIT')) ], ), ); }
Future<bool?> secondDialog(String someText) => showDialog<bool>( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(someText), content: Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Blah blah blah'), const SizedBox(height: 8), const Text('Blah blah blah'), const SizedBox(height: 8), const Text('Blah blah blah'), const SizedBox(height: 8), const Text('Blah blah blah'), ], ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(true), child: const Text('Continue')), ], ); });
原因分析与解决方案
这不是Flutter的bug,而是弹窗切换时的布局过渡逻辑导致的临时溢出:
- 第一个弹窗关闭后、第二个弹窗完全渲染前,Flutter会短暂复用前一个弹窗的布局约束;
- 当第二个弹窗内容高度超过前一个时,布局重新计算完成前就会出现瞬间的RenderFlex溢出提示。
最简单的解决方法是给第二个弹窗的content外层套上SingleChildScrollView,即使内容高度足够,它也能避免临时的约束冲突:
修改后的secondDialog代码:
Future<bool?> secondDialog(String someText) => showDialog<bool>( context: context, builder: (BuildContext context) { return AlertDialog( title: Text(someText), content: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Text('Blah blah blah'), const SizedBox(height: 8), const Text('Blah blah blah'), const SizedBox(height: 8), const Text('Blah blah blah'), const SizedBox(height: 8), const Text('Blah blah blah'), ], ), ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(true), child: const Text('Continue')), ], ); });
也可以给第一个弹窗的content也加上SingleChildScrollView,从根源避免切换时的约束冲突:
// 修改firstDialog的content部分 content: SingleChildScrollView( child: TextField( decoration: const InputDecoration( hintText: 'Enter something'), autofocus: true, controller: controller, onSubmitted: (_) { Navigator.of(context).pop(controller.text); controller.clear(); }), ),
两种方法都能彻底消除这个短暂的溢出提示。
内容的提问来源于stack exchange,提问作者Chris Nadovich
相关产品推荐
相关产品推荐

