Flutter Android TV应用按钮获得焦点后仍无法点击问题求助
问题根因
- 代码存在两层MaterialApp嵌套,内层MyHomePage返回的MaterialApp创建了独立的焦点管理上下文,和外层绑定快捷键的Shortcuts上下文隔离,第二次切换焦点后,提交按钮的焦点实际处于内层上下文,外层快捷键监听失效,导致遥控器确定键无法触发点击。
- 输入框提交时手动调用
unfocus()再请求新焦点的操作,会导致焦点树出现临时无焦点的状态,增加焦点状态不同步的概率。
解决方案
步骤1:移除重复的MaterialApp嵌套
删除_MyAppState.build方法中包裹Scaffold的MaterialApp,直接返回Scaffold即可,保证全局只有一个MaterialApp实例,共享同一个焦点和快捷键上下文。
步骤2:优化焦点切换逻辑
删除输入框onFieldSubmitted回调中的unfocus()调用,直接通过FocusScope.of(context).requestFocus()切换焦点即可,系统会自动处理旧焦点的失焦逻辑,避免焦点状态混乱。
步骤3:可选兼容优化
将废弃的FlatButton替换为新版的TextButton,避免旧组件的潜在焦点兼容问题。
修改后可运行完整代码
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Shortcuts( shortcuts: <LogicalKeySet, Intent>{ LogicalKeySet(LogicalKeyboardKey.select): ActivateIntent(), }, child: MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), ), ); } } class MyHomePage extends StatefulWidget { MyHomePage(); @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyHomePage> { FocusNode fname = FocusNode(); FocusNode age = FocusNode(); FocusNode submit = FocusNode(); @override void initState() { super.initState(); } @override void dispose() { fname.dispose(); age.dispose(); submit.dispose(); super.dispose(); } @override Widget build(BuildContext context) { // 移除了多余的MaterialApp嵌套,直接返回Scaffold return Scaffold( appBar: AppBar( title: Text('Focus Node'), centerTitle: true, ), body: Padding( padding: const EdgeInsets.all(16.0), child: SingleChildScrollView( child: Column( children: [ Text( 'Personal', style: TextStyle( fontSize: 40.0, fontWeight: FontWeight.w800, color: Colors.indigoAccent, ), ), TextFormField( autofocus: true, focusNode: fname, keyboardType: TextInputType.text, enabled: true, textInputAction: TextInputAction.next, decoration: InputDecoration( labelText: 'First Name', hintText: 'Enter your first name', border: OutlineInputBorder( borderSide: BorderSide(color: Colors.teal), ), ), onFieldSubmitted: (term) { // 移除了fname.unfocus()调用 FocusScope.of(context).requestFocus(age); }, ), SizedBox( height: 10, ), TextFormField( focusNode: age, enabled: true, keyboardType: TextInputType.text, textInputAction: TextInputAction.done, decoration: InputDecoration( labelText: 'Age', hintText: 'Enter your age', border: OutlineInputBorder( borderSide: BorderSide(color: Colors.teal), ), ), onFieldSubmitted: (term) { print('focus is -==========${submit.canRequestFocus} '); // 移除了age.unfocus()调用 FocusScope.of(context).requestFocus(submit); }, ), SizedBox( height: 10, ), TextButton( // 替换废弃的FlatButton为TextButton,也可以保留FlatButton不影响本次问题解决 autofocus: true, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(Colors.lightBlueAccent), foregroundColor: MaterialStateProperty.all(Colors.black), // 焦点高亮颜色保持原有逻辑 overlayColor: MaterialStateProperty.resolveWith((states) { if (states.contains(MaterialState.focused)) { return Colors.green; } return null; }) ), focusNode: submit, onPressed: () { print('Submit clicked'); }, child: Text('Submit'), ), ], ), ), )); } }
修改完成后重新运行,即可复现步骤中的操作场景,第二次切换到提交按钮后可正常触发点击事件。
内容的提问来源于stack exchange,提问作者Raghu Mudem
相关产品推荐
相关产品推荐

