resizeToAvoidBottomInset导致页面pop时短暂溢出问题求助
问题:Pop页面时出现短暂溢出错误
我有一个在Column中使用resizeToAvoidBottomInset属性的Widget,代码如下(已去除装饰等无关细节):
Widget build(BuildContext context) { return Scaffold( body: Column( children: [ TextField( maxLines: 1, maxLength: 6, controller: textController, ), Container(height: 16.0), const Spacer(), Container( alignment: Alignment.bottomCenter, child: ScreenWideButton("Update", onPressed: () { if (textController.text.length > 4) { widget.onChanged(int.parse(textController.text .substring(1, textController.text.length - 2))); Navigator.of(context).pop(); Fluttertoast.showToast(msg: "Changes saved"); } else { Fluttertoast.showToast(msg: "Please enter a valid value"); } }), ), const SizedBox(height: 10), ], ), resizeToAvoidBottomInset: true, ); }
该Widget正常使用无问题,但点击Update按钮pop回下方页面时,会出现短暂的溢出错误(动图为0.25倍速):
请问该问题原因是什么?如何修复?
原因分析
问题源于resizeToAvoidBottomInset: true的布局调整和页面Pop动画的时序冲突:
- 执行
Navigator.pop()时,当前页面启动退场动画,同时系统触发软键盘收起操作 resizeToAvoidBottomInset: true会让Scaffold跟随软键盘的收起动态调整自身高度,这个尺寸变化和页面退场动画同步进行- 页面主体是
Column+Spacer的固定布局结构,在尺寸快速变动的瞬间,Column的布局计算无法及时适配,从而出现短暂的布局溢出
修复方案
以下两种方案均可解决问题,按需选择:
方案1:延迟Toast显示,避开动画冲突
修改按钮点击逻辑,将Fluttertoast.showToast延迟执行,给页面足够时间完成退场和布局调整:
ScreenWideButton("Update", onPressed: () { if (textController.text.length > 4) { widget.onChanged(int.parse(textController.text .substring(1, textController.text.length - 2))); Navigator.of(context).pop(); // 延迟300ms显示Toast,适配页面退场动画时长 Future.delayed(const Duration(milliseconds: 300), () { Fluttertoast.showToast(msg: "Changes saved"); }); } else { Fluttertoast.showToast(msg: "Please enter a valid value"); } }),
方案2:用SingleChildScrollView包裹Column
让页面内容支持滚动,即使布局尺寸临时变化也不会触发溢出,同时保留软键盘避让功能:
body: SingleChildScrollView( child: Column( children: [ TextField( maxLines: 1, maxLength: 6, controller: textController, ), Container(height: 16.0), // 替换Spacer,因为ScrollView中Spacer失效,用SizedBox占据剩余空间 const SizedBox(height: double.infinity), Container( alignment: Alignment.bottomCenter, child: ScreenWideButton("Update", onPressed: () { // 原点击逻辑不变 }), ), const SizedBox(height: 10), ], // 设置Column最小高度为屏幕高度,保证布局和原效果一致 minHeight: MediaQuery.of(context).size.height, mainAxisSize: MainAxisSize.min, ), ),
注意:
SingleChildScrollView会让Column的高度自适应内容,因此需要给Column设置minHeight为屏幕高度,同时用SizedBox(height: double.infinity)替代Spacer来实现底部按钮的布局效果。
内容的提问来源于stack exchange,提问作者Ameen Izhac
相关产品推荐
相关产品推荐

