You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 19:03:11