Flutter:设置isDismissible:true时,点击模态屏障先关键盘再关底部弹窗
实现方案
核心思路是禁用默认的屏障关闭逻辑,手动接管屏障点击事件,同时通过Flutter原生API判断键盘状态,分情况执行「关闭键盘」或「关闭弹窗」操作。
1. 关键逻辑拆解
- 把
isDismissible设为false,取消默认的屏障点击关闭弹窗行为 - 用
barrierTapCallback自定义屏障点击后的处理逻辑 - 通过
MediaQuery.of(context).viewInsets.bottom判断键盘是否弹出:该值大于0时表示键盘处于显示状态 - 调用
FocusManager.instance.primaryFocus?.unfocus()关闭当前激活的软键盘
2. 完整代码示例
void showCustomBottomSheet(BuildContext context) { showModalBottomSheet( context: context, isDismissible: false, // 禁用默认关闭逻辑 barrierColor: Colors.black54, // 保持原有的半透明屏障样式 barrierTapCallback: () { // 判断键盘是否显示 bool isKeyboardShow = MediaQuery.of(context).viewInsets.bottom > 0; if (isKeyboardShow) { // 关闭键盘,弹窗保留 FocusManager.instance.primaryFocus?.unfocus(); } else { // 关闭弹窗 Navigator.pop(context); } }, builder: (context) { // 适配键盘高度,避免输入框被遮挡 return Padding( padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom), child: Container( height: 220, padding: const EdgeInsets.all(16), child: Column( children: [ TextField(decoration: const InputDecoration(hintText: "输入内容测试键盘")), const SizedBox(height: 20), const Text("点击外部区域测试逻辑"), ], ), ), ); }, ); }
3. 细节说明
- 弹窗内的输入框通过
padding适配键盘高度,保证输入区域始终可见 - 如果页面有多个可聚焦组件,
primaryFocus会自动定位到当前激活的输入框,确保关闭对应键盘 - 若遇到键盘动画过程中判断不准的情况,可以加个短延迟:
Future.delayed(const Duration(milliseconds: 100), () { bool isKeyboardShow = MediaQuery.of(context).viewInsets.bottom > 0; // 后续逻辑不变 });
内容的提问来源于stack exchange,提问作者Eng
相关产品推荐
相关产品推荐

