我花了很多时间来理解为什么它不起作用,但仍然不知道如何修复它。 我找到了这个解决方案 https://github.com/flutter/flutter/issues/49783 ,但它对我没有帮助。 我的问题是按下 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" />
我在为 android 电视制作 IPTV 应用程序时也遇到了这个问题,每当焦点转移到文本字段之后我无法使用电视遥控器的 Enter 按钮但我注意到如果按两次向下按钮和一次向上按钮计时 Enter 按钮再次开始工作 原因仍然未知,这是一个悬而未决的问题,唯一的解决方案是通过创建屏幕键盘和点击时的映射值来填充文本字段 希望这有帮助
我不确定我是否迟到了,但这是 Android TV 方向键导航的固定解决方法。
请注意,在文本字段中,我们需要读取 keyUp 事件。这是因为 Android TV 上的键盘似乎读取了 keyUp 事件。因此,如果按下 keyDown,将出现键盘,如果释放该键,将触发 keyUp 事件,该事件将从键盘获取输入。这就是为什么所有操作都在 keyUp 上完成的原因。 (我花了一周时间为我的应用解决这个问题)
如果文本字段已经有焦点,我们需要添加一个包装器,使文本字段成为选择键的焦点。 (这只是一种解决方法)
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;