Flutter中requestFocus()在Android模拟器生效,Web端Chrome无响应问题
Flutter Web端焦点切换失效问题解决(Android正常,Chrome异常)
你的代码在Android模拟器中能通过「Move focus」按钮正常切换两个输入框的焦点,但在Chrome Web端焦点始终停留在input 1,核心问题出在FocusScopeNode的缓存方式和Web端焦点管理的特性差异上。
问题根源
- 你通过
fcn ??= FocusScope.of(context)缓存了FocusScopeNode,但Web端的FocusScope在组件状态变化时可能会更新,缓存的节点会失效,导致后续焦点请求无法生效。 - 直接对比
fcn?.focusedChild的方式在Web端无法准确获取当前焦点状态,和原生平台的焦点判断逻辑存在差异。
修正后的代码
class FocusTestRoute extends StatefulWidget { const FocusTestRoute({super.key}); @override State<FocusTestRoute> createState() => _FocusTestRouteState(); } class _FocusTestRouteState extends State<FocusTestRoute> { late FocusNode fn1; late FocusNode fn2; @override void initState() { super.initState(); fn1 = FocusNode(); fn2 = FocusNode(); // 初始化后手动请求input1焦点,替代autofocus避免Web端状态不一致 WidgetsBinding.instance.addPostFrameCallback((_) { fn1.requestFocus(); }); } @override void dispose() { fn1.dispose(); fn2.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.all(16.0), child: Column( children: <Widget>[ TextField( focusNode: fn1, decoration: const InputDecoration( labelText: "input 1", ), ), TextField( focusNode: fn2, decoration: const InputDecoration( labelText: "input 2", ), ), const SizedBox(height: 30), ElevatedButton( onPressed: () { // 每次点击都获取当前有效的FocusScopeNode final focusScope = FocusScope.of(context); // 通过FocusNode的hasFocus属性判断焦点,Web端更可靠 if (fn1.hasFocus) { focusScope.requestFocus(fn2); } else { focusScope.requestFocus(fn1); } }, child: const Text('Move focus'), ), ], ), ); } }
关键修改说明
- 移除了缓存的
FocusScopeNode,每次点击按钮时实时获取当前的FocusScope.of(context),确保使用的是有效节点。 - 改用
FocusNode.hasFocus判断焦点状态,这个属性在Web端和原生平台的表现一致,能准确反映当前输入框是否获得焦点。 - 把
autofocus: true替换为initState中手动请求焦点,避免Web端自动聚焦可能引发的状态不同步问题。 - 完善了
FocusNode的生命周期管理,在组件销毁时释放资源,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Pauli
相关产品推荐
相关产品推荐

