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

Android平台Flutter应用切换时保持软键盘常驻的实现方案

问题描述

初始场景:

  • 应用中的文本框已获取焦点,软键盘处于打开状态。
  • 用户临时切换至其他应用。

预期效果:

  • 用户切回应用时,软键盘立即就绪。

实际情况:软键盘被隐藏,需重新点击文本框才能唤起。

Flutter当前实现(存在问题):

通过WidgetsBindingObserver监听应用回到前台,调用SystemChannels.textInput.invokeMethod('TextInput.show')重新显示键盘,但会出现软键盘先隐藏再显示的闪烁问题,体验不佳:
Flutter闪烁问题演示动图

Compose原生实现(理想效果):

Android原生Compose的文本框不会出现此问题,软键盘全程保持打开状态,这正是期望在Flutter中实现的效果:
Compose理想效果演示动图

已尝试方案

  • 修改AndroidManifest.xml中的android:windowSoftInputMode属性,但未出现任何改善或变化。

相关代码

Compose实现代码:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            parent
            Box(
                modifier = Modifier
                    .fillMaxHeight(),
                contentAlignment = Alignment.Center
            ) {
                TextField(
                    modifier = Modifier.fillMaxWidth(),
                    value = "", onValueChange = {}
                )
            }
        }
    }
}

Flutter当前最优实现代码:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(
    const App(),
  );
}

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({super.key});

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> with WidgetsBindingObserver {
  final _focusNode = FocusNode();
  late final TextEditingController _controller;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    _focusNode.dispose();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed) {
      SystemChannels.textInput.invokeMethod('TextInput.show');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: TextField(
          focusNode: _focusNode,
          controller: _controller,
          autofocus: true,
        ),
      ),
    );
  }
}

问题

如何在Android平台的Flutter应用中实现:用户切换应用后返回时,文本框的软键盘立即显示?

解决方案

1. 原生层拦截生命周期回调(推荐)

Flutter Android端默认会在应用退到后台时销毁TextInputConnection,导致软键盘收起。通过自定义FlutterActivity,直接在原生层处理焦点与软键盘状态,从根源避免闪烁:

创建自定义FlutterActivity:

import android.content.Context
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import io.flutter.embedding.android.FlutterActivity

class CustomFlutterActivity : FlutterActivity() {
    private var shouldKeepKeyboard = false

    override fun onPause() {
        val currentFocus = currentFocus
        shouldKeepKeyboard = currentFocus is EditText && currentFocus.hasFocus()
        super.onPause()
    }

    override fun onResume() {
        super.onResume()
        if (shouldKeepKeyboard) {
            currentFocus?.requestFocus()
            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            imm.showSoftInput(currentFocus, InputMethodManager.SHOW_IMPLICIT)
        }
    }
}

在AndroidManifest.xml中替换默认的FlutterActivity为自定义的CustomFlutterActivity即可。

2. Flutter层优化焦点管理

通过记录退到后台前的焦点状态,回到前台时延迟请求焦点,利用Flutter焦点系统自动唤起软键盘,减少闪烁:

class _HomeState extends State<Home> with WidgetsBindingObserver {
  final _focusNode = FocusNode();
  late final TextEditingController _controller;
  bool _wasFocusedBeforePause = false;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
    WidgetsBinding.instance.addObserver(this);
    _focusNode.addListener(() {
      if (_focusNode.hasFocus) {
        _wasFocusedBeforePause = true;
      }
    });
  }

  @override
  void dispose() {
    _focusNode.dispose();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed) {
      if (_wasFocusedBeforePause && !_focusNode.hasFocus) {
        Future.delayed(const Duration(milliseconds: 100), () {
          if (mounted) {
            _focusNode.requestFocus();
          }
        });
      }
    } else if (state == AppLifecycleState.paused) {
      _wasFocusedBeforePause = _focusNode.hasFocus;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Center(
        child: TextField(
          focusNode: _focusNode,
          controller: _controller,
          autofocus: true,
        ),
      ),
    );
  }
}

内容的提问来源于stack exchange,提问作者Stefan Wurzelsand

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 12:25:56