Android平台Flutter应用切换时保持软键盘常驻的实现方案
问题描述
初始场景:
- 应用中的文本框已获取焦点,软键盘处于打开状态。
- 用户临时切换至其他应用。
预期效果:
- 用户切回应用时,软键盘立即就绪。
实际情况:软键盘被隐藏,需重新点击文本框才能唤起。
Flutter当前实现(存在问题):
通过WidgetsBindingObserver监听应用回到前台,调用SystemChannels.textInput.invokeMethod('TextInput.show')重新显示键盘,但会出现软键盘先隐藏再显示的闪烁问题,体验不佳:
Compose原生实现(理想效果):
Android原生Compose的文本框不会出现此问题,软键盘全程保持打开状态,这正是期望在Flutter中实现的效果:
已尝试方案
- 修改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
相关产品推荐
相关产品推荐

