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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 23:54:02