flutter 修复Android TV上控件的焦点

6ojccjat  于 2023-04-13  发布在  Flutter
关注(0)|答案(3)|浏览(326)

我花了很多时间来理解为什么它不工作,但仍然不知道如何修复它.我发现这个解决方案https://github.com/flutter/flutter/issues/49783,但它没有帮助我.我的问题是开关不改变按下RC上的选择按钮(我使用模拟器).重现的步骤:

  • 启动应用程序
  • 在第一个文本控件中输入一些文本(在我的情况下,我需要按下和向上按钮来显示键盘,这是另一个错误,这可能是很酷的修复)
  • 按下返回遥控按钮(顺便说一句,如果你知道如何使用提交这里,让我知道)隐藏键盘
  • 按下RC按钮-焦点将转到开关
  • 然后尝试按下选择按钮(它的作品第一次)
  • 然后返回到文本字段,按下返回,然后向下RC按钮
  • 现在开关不工作按选择
  • 按下选择按钮仍然不起作用
  • 按向上-选择是切换开关和按钮再次工作!如果你去文本字段,那么它会重复

我的示例代码:

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return Shortcuts(
      shortcuts: <LogicalKeySet, Intent>{
        LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
      },
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(),
      ),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool switchValue = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Demo Home Page'),
      ),
      body: Center(
        child: Column(
          // mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: EdgeInsets.symmetric(vertical: 10),
              child: Focus(
                canRequestFocus: false,
                onKey: (FocusNode node, RawKeyEvent event) {
                  if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
                    FocusManager.instance.primaryFocus!
                        .focusInDirection(TraversalDirection.left);
                  } else if (event.logicalKey ==
                      LogicalKeyboardKey.arrowRight) {
                    FocusManager.instance.primaryFocus!
                        .focusInDirection(TraversalDirection.right);
                  } else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
                    FocusManager.instance.primaryFocus!
                        .focusInDirection(TraversalDirection.up);
                  } else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
                    FocusManager.instance.primaryFocus!
                        .focusInDirection(TraversalDirection.down);
                  }
                  return KeyEventResult.handled;
                },
                child: TextField(
                  autofocus: true,
                ),
              ),
            ),
            Switch(
              value: switchValue,
              onChanged: (value) {
                setState(() {
                  switchValue = value;
                });
              },
            ),
            TextButton(
              onPressed: () => print('Button pressed'),
              style: TextButton.styleFrom(
                shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.circular(18.0),
                ),
              ),
              child: const Text('Test'),
            ),
          ],
        ),
      ),
    );
  }
}

这是我的AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.testfocus.test_focus">
<application
     android:label="test_focus"
     android:name="${applicationName}"
     android:icon="@mipmap/ic_launcher">
    <activity
        android:name=".MainActivity"
        android:exported="true"
        android:launchMode="singleTop"
        android:theme="@style/LaunchTheme"
        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
        android:hardwareAccelerated="true"
        android:windowSoftInputMode="adjustResize">
        <!-- Specifies an Android theme to apply to this Activity as soon as
             the Android process has started. This theme is visible to the user
             while the Flutter UI initializes. After that, this theme continues
             to determine the Window background behind the Flutter UI. -->
        <meta-data
          android:name="io.flutter.embedding.android.NormalTheme"
          android:resource="@style/NormalTheme"
          />
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
            <category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
            <category android:name="android.intent.category.LAUNCHER"/>
        </intent-filter>
    </activity>
    <!-- Don't delete the meta-data below.
         This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
    <meta-data
        android:name="flutterEmbedding"
        android:value="2" />
</application>
<uses-feature android:name="android.software.leanback" android:required="false" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
oogrdqng

oogrdqng1#

我在使用Flutter开发电视应用程序时遇到了类似的问题。
因为textfield有它自己焦点,我找到了一个解决方法。
我禁用了文本字段的输入,并出现在屏幕键盘上,用于在文本字段内输入值。
比如这个:

根据按钮按下字符在文本字段上分配值这将是很好的解决方法和更用户友好.尝试最大限度地减少用户输入,同时开发电视应用程序与Flutter.

r3i60tvu

r3i60tvu2#

我也面临着这个问题,而使一个IPTV应用程序的Android电视每当焦点转移到一个文本字段后,我无法使用电视遥控器的回车键,但我注意到,如果按两次向下按钮和一次向上按钮回车键开始再次工作的原因仍然未知这是一个开放的问题,唯一的解决方案是通过创建一个屏幕键盘和Map值来填充文本字段,希望这能有所帮助

toe95027

toe950273#

我不确定我是否迟到了,但这里是Android TV的D-pad导航的固定解决方案。
请注意,在文本字段中,我们需要读取keyUp事件。这是因为Android TV上的键盘似乎会读取keyUp事件。因此,如果按下keyDown,键盘将出现,如果释放键,则会触发keyUp事件,这将从键盘获取输入。这就是为什么所有操作都在keyUp上完成。(我花了一周的时间来修复我的应用程序的这个问题)
如果文本字段已经有焦点,我们需要添加一个 Package 器,使文本字段在选择键下有焦点。(这只是一个解决方法)

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return Shortcuts(
      shortcuts: <LogicalKeySet, Intent>{
        LogicalKeySet(LogicalKeyboardKey.select): const ActivateIntent(),
      },
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const MyHomePage(),
      ),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool switchValue = false;
  final FocusScopeNode node = FocusScopeNode();
  final textFocus = FocusNode();
  final textWrapper = FocusNode();
  final switchFocus = FocusNode();
  final btnNode = FocusNode();

  @override
  void initState() {
    textFocus.addListener(_listener);
    btnNode.addListener(_listener);
    textWrapper.addListener(_listener);
    switchFocus.addListener(_listener);
    super.initState();
  }

  _listener() {
    if (textFocus.hasFocus ||
        textWrapper.hasFocus ||
        switchFocus.hasFocus ||
        btnNode.hasFocus) {
      setState(() {});
    }
  }

  @override
  void dispose() {
    textFocus.removeListener(_listener);
    btnNode.removeListener(_listener);
    textWrapper.removeListener(_listener);
    switchFocus.removeListener(_listener);
    node.dispose();
    textFocus.dispose();
    switchFocus.dispose();
    btnNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Demo Home Page'),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(vertical: 10),
        child: FocusScope(
          autofocus: true,
          onFocusChange: (val) {
            if (val) textFocus.requestFocus();
          },
          onKey: (FocusNode node, RawKeyEvent event) {
            if (event is RawKeyUpEvent &&
                event.data is RawKeyEventDataAndroid) {
              RawKeyUpEvent rawKeyDownEvent = event;
              RawKeyEventDataAndroid rawKeyEventDataAndroid =
                  rawKeyDownEvent.data as RawKeyEventDataAndroid;

              if (rawKeyEventDataAndroid.keyCode == KEY_CENTER) {
                if (textFocus.hasFocus) {
                  textFocus.unfocus();
                  Future.delayed(Duration.zero).then((value) {
                    textFocus.requestFocus();
                  });
                } else if (textWrapper.hasFocus) {
                  textFocus.requestFocus();
                }
              }

              if (rawKeyEventDataAndroid.keyCode == KEY_DOWN) {
                if (textWrapper.hasFocus) {
                  switchFocus.requestFocus();
                } else if (switchFocus.hasFocus) {
                  btnNode.requestFocus();
                } else {
                  textFocus.requestFocus();
                }
              }

              if (rawKeyEventDataAndroid.keyCode == KEY_UP) {
                if (btnNode.hasFocus) {
                  switchFocus.requestFocus();
                } else if (switchFocus.hasFocus) {
                  textFocus.requestFocus();
                } else {
                  btnNode.requestFocus();
                }
              }
            }
            return KeyEventResult.handled;
          },
          child: Column(
            children: [
              RawKeyboardListener(
                focusNode: textWrapper,
                child: TextField(
                  focusNode: textFocus,
                  autofocus: true,
                ),
              ),
              Shortcuts(
                shortcuts: <LogicalKeySet, Intent>{
                  LogicalKeySet(LogicalKeyboardKey.select):
                      const ActivateIntent(),
                  LogicalKeySet(LogicalKeyboardKey.enter):
                      const ActivateIntent(),
                },
                child: Switch(
                  value: switchValue,
                  focusNode: switchFocus,
                  onChanged: (value) {
                    setState(() {
                      switchValue = value;
                    });
                  },
                ),
              ),
              Shortcuts(
                shortcuts: <LogicalKeySet, Intent>{
                  LogicalKeySet(LogicalKeyboardKey.select):
                      const ActivateIntent(),
                  LogicalKeySet(LogicalKeyboardKey.enter):
                      const ActivateIntent(),
                },
                child: TextButton(
                  onPressed: () => print('Button pressed'),
                  focusNode: btnNode,
                  style: TextButton.styleFrom(
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(18.0),
                    ),
                  ),
                  child: const Text('Test'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

const int KEY_UP = 19;
const int KEY_DOWN = 20;
const int KEY_LEFT = 21;
const int KEY_RIGHT = 22;
const int KEY_CENTER = 23;
const int KEY_BACK = 4;

相关问题