Flutter:解决返回时键盘关闭后页面A出现UI抖动的问题
解决Flutter返回时键盘收起导致页面抖动的问题
在页面B的AppBar返回按钮点击时,若当前TextField处于聚焦状态(键盘打开),直接返回页面A会导致A出现UI抖动——这是因为键盘收起动画和页面跳转动画同时执行,引发布局冲突。
你之前的解决方案用固定延迟避开了冲突,但await后使用context不符合Dart规范,因为异步间隙内context对应的Widget可能已被销毁,存在潜在错误。以下是几种更安全的替代方案:
方案一:提前获取Navigator实例,避免异步后使用context
提前获取Navigator对象,后续操作直接使用该实例而非context,彻底规避异步状态下context失效的风险:
onPressed: () async { // 提前获取Navigator实例 final navigator = Navigator.of(context); // 触发键盘收起 FocusScope.of(context).unfocus(); // 等待键盘收起动画完成(可根据设备适配调整延迟时长) await Future.delayed(const Duration(milliseconds: 250)); // 执行页面返回 navigator.maybePop(); },
方案二:监听焦点变化,焦点失去后再跳转
通过监听焦点节点的状态变化,确保键盘完全收起(焦点已释放)后再执行页面返回,无需依赖固定延迟:
onPressed: () { final navigator = Navigator.of(context); final focusedNode = FocusScope.of(context).focusedChild?.focusNode; // 定义焦点变化回调 void handleFocusChange(bool hasFocus) { if (!hasFocus) { // 移除监听,避免内存泄漏 focusedNode?.removeListener(handleFocusChange); // 执行返回 navigator.maybePop(); } } if (focusedNode != null) { focusedNode.addListener(handleFocusChange); } // 触发键盘收起 FocusScope.of(context).unfocus(); // 处理无焦点节点的边界情况(比如未点击TextField直接返回) if (focusedNode == null) { navigator.maybePop(); } },
方案三:监听键盘视图Insets,确认收起后跳转
直接监听系统视图的Insets变化,精准判断键盘是否完全收起,是适配性最强的方案:
onPressed: () { final navigator = Navigator.of(context); // 触发键盘收起 FocusScope.of(context).unfocus(); // 定义检查键盘状态的回调 void checkKeyboardStatus(_) { final isKeyboardClosed = WidgetsBinding.instance.window.viewInsets.bottom == 0; if (isKeyboardClosed) { // 移除监听,避免不必要的资源消耗 WidgetsBinding.instance.removePersistentFrameCallback(checkKeyboardStatus); // 执行页面返回 navigator.maybePop(); } } // 添加帧回调,持续检查键盘状态 WidgetsBinding.instance.addPersistentFrameCallback(checkKeyboardStatus); },
方案对比
- 方案一:实现简单,适合多数场景,但延迟时长需根据设备适配调整,存在小概率适配问题。
- 方案二:逻辑清晰,无固定延迟,但需处理无焦点的边界情况。
- 方案三:精准监听键盘状态,适配所有设备,但代码相对复杂。
内容的提问来源于stack exchange,提问作者Sayyid J
相关产品推荐
相关产品推荐

