Flutter TextField在Android 16 Beta/OxygenOS 16中键盘弹出后立即消失
TextField点击后软键盘立即收起(Android 16及定制系统兼容问题)
问题现象
- 用户点击TextField后,软键盘开始弹出动画
- 动画完成前键盘自动回弹关闭,TextField同步失去焦点
- 完全无法输入文本,阻断用户流程
受影响设备与系统版本
- vivo X300/Motorola Edge 50 Pro:Android 16 Beta(API 36)
- OnePlus 11:OxygenOS 16.0.3.500
- realme 9 Pro+:Android 14(出现类似症状)
技术背景
该问题与Android 16强制的Edge-to-Edge机制相关:键盘调整窗口大小时,Window Inset过渡触发了布局冲突或pointer cancel事件,被Flutter解读为失焦请求,导致TextField失去焦点、键盘收起。
已尝试无效方案
- 在
initState中初始化TextEditingController和FocusNode,避免重建导致失焦 - 为
Scaffold设置resizeToAvoidBottomInset: true - 用
SafeArea和SingleChildScrollView包裹输入区域 - 在
AndroidManifest.xml中测试adjustResize和adjustPan软输入模式 - 移除背景
GestureDetectors,排除意外调用unfocus()的可能
针对性解决方案
1. 监听FocusNode意外失焦,强制重新获取焦点
通过FocusNode的状态监听,在意外失焦时延迟重新请求焦点,避开键盘动画的冲突窗口:
import 'package:flutter/material.dart'; void main() => runApp(const MaterialApp(home: LoginScreen())); class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); @override State<LoginScreen> createState() => _LoginScreenState(); } class _LoginScreenState extends State<LoginScreen> { final FocusNode _focusNode = FocusNode(); @override void initState() { super.initState(); _focusNode.addListener(() { // 当焦点意外丢失时,延迟100ms重新请求焦点 if (!_focusNode.hasFocus) { Future.delayed(const Duration(milliseconds: 100), () { if (mounted) { _focusNode.requestFocus(); } }); } }); } @override void dispose() { _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: true, body: SafeArea( child: SingleChildScrollView( child: Column( children: [ const SizedBox(height: 300), TextField( focusNode: _focusNode, decoration: const InputDecoration(hintText: "Enter Mobile Number"), ), ], ), ), ), ); } }
2. 禁用Android原生Edge-to-Edge强制Insets处理
在AndroidManifest.xml中为目标Activity指定自定义主题,关闭windowDecorFitsSystemWindows:
<activity android:name=".MainActivity" android:windowSoftInputMode="adjustResize" android:theme="@style/Theme.App.NoEdgeToEdge">
在res/values/styles.xml中定义主题:
<style name="Theme.App.NoEdgeToEdge" parent="Theme.Material3.Light.NoActionBar"> <item name="android:windowDecorFitsSystemWindows">true</item> </style>
该设置会强制系统使用传统的窗口Insets处理逻辑,避免Edge-to-Edge机制导致的布局冲突。
3. 手动处理Flutter窗口Insets
通过MediaQuery.removePadding移除底部Insets,配合SingleChildScrollView避免布局挤压触发的失焦:
@override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: true, body: MediaQuery.removePadding( context: context, removeBottom: true, child: SafeArea( child: SingleChildScrollView( child: Column( children: [ const SizedBox(height: 300), TextField( focusNode: _focusNode, decoration: const InputDecoration(hintText: "Enter Mobile Number"), ), ], ), ), ), ), ); }
4. 升级Flutter版本
该问题大概率是Flutter与Android 16 Beta的兼容性bug,建议升级到最新的Flutter稳定版或beta版,官方可能已修复相关Insets处理逻辑。
内容的提问来源于stack exchange,提问作者Shivam Singh
相关产品推荐
相关产品推荐

