Flutter Web - 快捷键和操作小部件不会在页面级别监听键盘事件以提供键盘快捷键

Jam*_*ark 6 flutter flutter-web

在我的用例中,我在特定页面中有多个布局。例如,在一个页面中,我有布局(比如说布局1),我使用文本字段列表从用户那里获取输入数据,然后在同一页面中,我在底部有另一个布局(比如说布局2)其中表格小部件用于逐行列出我们从用户收到的数据。同样,我在同一页面中有其他布局。我试图通过使用 control + D、control + R 等提供键盘快捷键,所以我面临的问题是,如果我专注于布局 1 中的文本字段,然后按键盘键 control + D正确地聚焦预期的小部件。但是如果我在文本域之外单击(特定页面屏幕上的任何位置),那么它就会失去焦点。现在,如果我单击 Control + D,快捷方式和操作小部件不会侦听键盘事件。

为了显示这个问题,我只是在此处创建了简单的代码,并且在该代码中,如果我单击文本字段之外并且尝试使用 control + D,则它不起作用。

例如,在下面的代码中,我有两个文本字段,我根据快捷方式专注于这些文本字段(这只是解释问题的示例)。control + R 是聚焦于文本字段 1,control + D 是聚焦于文本字段 2。它工作正常。但是如果我单击文本字段之外的某个位置,然后尝试快捷方式,它不会侦听键盘事件。它会失去焦点。

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

class KeyboardShortcutTesting extends StatelessWidget {
  KeyboardShortcutTesting({Key? key}) : super(key: key);

  final FocusNode textfield1FocusNode = FocusNode();
  final FocusNode textfield2FocusNode = FocusNode();

  @override
  Widget build(BuildContext context) {
    return Shortcuts(
      shortcuts: {
        LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyR):
            Testfield1ShorcutIntent(),
        LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyD):
            Testfield2ShorcutIntent(),
      },
      child: Actions(
        actions: {
          Testfield1ShorcutIntent:
              CallbackAction<Testfield1ShorcutIntent>(onInvoke: (intent) {
            print('clicked cnrl + D');
            return textfield1FocusNode.requestFocus();
          }),
          Testfield2ShorcutIntent:
              CallbackAction<Testfield2ShorcutIntent>(onInvoke: (intent) {
            print('clicked cnrl + R');
            return textfield2FocusNode.requestFocus();
          }),
        },
        child: Focus(
          autofocus: true,
          child: Scaffold(
              appBar: AppBar(title: const Text('Keyboard shortcut testing')),
              body: Center(
                child: Card(
                  color: Colors.amber[50],
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: SizedBox(
                      width: 300,
                      height: 200,
                      child: Column(
                        children: [
                          TextField(
                            focusNode: textfield1FocusNode,
                            decoration: const InputDecoration(
                              border: OutlineInputBorder(),
                            ),
                          ),
                          const SizedBox(height: 10),
                          TextField(
                            focusNode: textfield2FocusNode,
                            decoration: const InputDecoration(
                              border: OutlineInputBorder(),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              )),
        ),
      ),
    );
  }
}

class Testfield1ShorcutIntent extends Intent {}

class Testfield2ShorcutIntent extends Intent {}
Run Code Online (Sandbox Code Playgroud)

我正在为 flutter web 尝试这段代码。我还附上一张图片来显示问题。在这里,如果我将焦点放在 textfield1 或 texfield2 上,然后如果我按 control + D 或 control + R,则焦点将根据逻辑在文本字段之间切换,但我单击文本字段外部(黄色卡中或外部的任何位置)黄色卡)然后如果我按下则快捷键不起作用,因为它甚至不听按键。 在此输入图像描述

注意:我还尝试使用 FocusScope 小部件而不是 Focus 小部件,但 FocusScope 小部件不允许在外部聚焦。对于前。如果我使用 FocusScope 小部件并且如果我单击文本字段之外,则它不允许,因为焦点不会从文本字段中出来。它持续关注同一个文本字段小部件。

感谢您的回应!

Ana*_*nas 1

  • Flutter Docs 建议用于Stateful Widget创建FocusNode
  • Flutter 提供预构建 Intent 来请求焦点 ->RequestFocusIntent(focusNode1)

尝试下面的代码,

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

  @override
  State<TextFieldShortcut> createState() => _TextFieldShortcutState();
}

class _TextFieldShortcutState extends State<TextFieldShortcut> {

  late final FocusNode focusNode1, focusNode2;

  @override
  void initState() {
    super.initState();
    focusNode1 = FocusNode();
    focusNode2 = FocusNode();
  }

  @override
  void dispose() {
    focusNode1.dispose();
    focusNode2.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Shortcuts(
      shortcuts: {
        LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyM): 
        RequestFocusIntent(focusNode1),
        LogicalKeySet(LogicalKeyboardKey.controlLeft, LogicalKeyboardKey.keyQ): 
        RequestFocusIntent(focusNode2),
      },
      child: MaterialApp(
        home: Scaffold(
          body: Center(
            child: Column(
              children: [
                TextField(
                  autofocus: true,
                  focusNode: focusNode1,
                ),
                TextField(
                  focusNode: focusNode2,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)