【问题标题】:Flutter RawKeyboardListener listening twice?Flutter RawKeyboardListener 听了两次?
【发布时间】:2018-06-22 09:51:05
【问题描述】:

我想要实现的是在查看此小部件时,RawKeyboardListener 会在 TextField 未被选中/处于焦点时立即开始收听。它运行HandleKey function 来处理我想用keyCode 做的事情。

我遇到的问题是第一次运行应用程序时,handleKey function 似乎运行了两次。因此,在下面的示例中,当我只输入 1 个键时,它会打印 why does this run twice $_keyCode TWICE。我认为它会听 keyUp 和 keyDown。我想要的结果是它只运行一次......

但是,当我选择 TextField 并使用模拟器键盘进行常规提交时,代码也可以正常工作。

我很难理解为什么它只有在与 TextField 交互后才会出现问题。我觉得它需要Futureawait 某处?但我不知道。

请帮忙。

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

class KeyboardListener extends StatefulWidget {

    KeyboardListener();

    @override
    _RawKeyboardListenerState createState() => new _RawKeyboardListenerState();
}

class _RawKeyboardListenerState extends State<KeyboardListener> {

    TextEditingController _controller = new TextEditingController();
    FocusNode _textNode = new FocusNode();


    @override
        initState() {
        super.initState();
    }
    
    //Handle when submitting
    void _handleSubmitted(String finalinput) {

        setState(() {
            SystemChannels.textInput.invokeMethod('TextInput.hide'); //hide keyboard again
            _controller.clear();
        });
    }

    handleKey(RawKeyEventDataAndroid key) {
        String _keyCode;
        _keyCode = key.keyCode.toString(); //keycode of key event (66 is return)

        print("why does this run twice $_keyCode");
    }

    _buildTextComposer() {
        TextField _textField = new TextField(
            controller: _controller,
            onSubmitted: _handleSubmitted,
        );

        FocusScope.of(context).requestFocus(_textNode);

        return new RawKeyboardListener(
            focusNode: _textNode,
            onKey: (key) => handleKey(key.data),
            child: _textField
        );
    }


  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(title: new Text("Search Item")),
      body: _buildTextComposer(),
    );
  }
}

【问题讨论】:

  • 这是为了通知按键和按键释放。

标签: android dart flutter


【解决方案1】:

keydown 和 keyup 事件都会调用您的回调,并带有以下类的实例:

  • RawKeyDownEvent
  • RawKeyUpEvent

您可以将整个对象传递给handleKey,并根据对象的运行时类型进行过滤。例如

  handleKey(RawKeyEvent key) {
    print("Event runtimeType is ${key.runtimeType}");
    if(key.runtimeType.toString() == 'RawKeyDownEvent'){
        RawKeyEventDataAndroid data = key.data as RawKeyEventDataAndroid;
        String _keyCode;
        _keyCode = data.keyCode.toString(); //keycode of key event (66 is return)

        print("why does this run twice $_keyCode");
    }
  }

  _buildTextComposer() {
      TextField _textField = new TextField(
          controller: _controller,
          onSubmitted: _handleSubmitted,
      );

      FocusScope.of(context).requestFocus(_textNode);

      return new RawKeyboardListener(
          focusNode: _textNode,
          onKey: handleKey,
          child: _textField
      );
  }

如果这仍然没有帮助,请检查从 handleKey 方法记录的实际 runtimeTypes,并按这些进行过滤。

【讨论】:

  • afaik 这个监听器只适用于物理键盘,它不适用于“软”键盘,对吧?
  • 我宁愿使用 instance-of kind 运算符:key is RawKeyDownEvent
  • 请注意,这在 runtimeType 将被优化的生产版本中不起作用,即不可用。
【解决方案2】:

使用isKeyPressed 对我有用。

我的工作代码

RawKeyboardListener(
                  focusNode: _focusNodeKeyboard,
                  onKey: (event) {
                    if (event.isKeyPressed(LogicalKeyboardKey.backspace)) {
                      print('Backspace Pressed'); // Printed Once
                    }
                  },
                )

旧版本

RawKeyboardListener(
                  focusNode: _focusNodeKeyboard,
                  onKey: (event) {
                    if (event.logicalKey == LogicalKeyboardKey.backspace) {
                     print('Backspace Pressed'); // Printed Twice
                    }
                  },
                )

【讨论】:

    【解决方案3】:

    我更喜欢使用is 而不是访问运行时类型:

    onKey: (RawKeyEvent event) {
      if (event is RawKeyDownEvent) {
        // handle key down
      } else if (event is RawKeyUpEvent) {
        // handle key up
      }
    },
    

    【讨论】:

      【解决方案4】:

      Eyo,玩弄了 values 变量,发现如果你使用 iskeypressed 在第二轮它是错误的。我冒昧地猜测一下,它通常会检测到新闻和发布。

      所以

          RawKeyboardListener(
                      focusNode: FocusNode(),
                      autofocus: true,
                      //includeSemantics: true,
                      onKey: (value){
      
                        print("1) ${value.data}");
                        print("2) ${value.character.toString()}");
                        print("3) ${value.toString()}");
                        print("4) ${value.physicalKey.debugName}");
                        print("5) ${value.logicalKey.keyId}");
                        print("6) ${value.isKeyPressed(LogicalKeyboardKey.enter)}");
      
      
                        setState(() {
                         
                          ///add string to list and clear text or not ?
                          value.logicalKey == LogicalKeyboardKey.enter ? print("YES A") : 0;
                          value.isKeyPressed(LogicalKeyboardKey.enter) ? print("YES B") : 0;
                          }
                        );
                      },
      

      结果

          flutter: 1) Instance of 'RawKeyEventDataWindows'
      flutter: 2) 
      
      flutter: 3) RawKeyDownEvent#13d45(logicalKey: LogicalKeyboardKey#70028(keyId: "0x100070028", keyLabel: "Enter", debugName: "Enter"), physicalKey: PhysicalKeyboardKey#70028(usbHidUsage: "0x00070028", debugName: "Enter"))
      flutter: 4) Enter
      flutter: 5) 4295426088
      flutter: 6) true
      flutter: YES A
      flutter: YES B
      flutter:  NEXT SET
      flutter: ***********************************
      flutter: 1) Instance of 'RawKeyEventDataWindows'
      flutter: 2) null
      flutter: 3) RawKeyUpEvent#9dc07(logicalKey: LogicalKeyboardKey#70028(keyId: "0x100070028", keyLabel: "Enter", debugName: "Enter"), physicalKey: PhysicalKeyboardKey#70028(usbHidUsage: "0x00070028", debugName: "Enter"))
      flutter: 4) Enter
      flutter: 5) 4295426088
      flutter: 6) false
      flutter: YES A
      flutter:  NEXT SET
      flutter: ***********************************
      

      【讨论】:

      • 啊刚刚实现 RawKeyUpEvent#9dc07 RawKeyDownEvent#13d45
      【解决方案5】:

      你是对的。 RawKeyboardListener 监听原始键盘事件。这意味着它会向下和向上返回(或命名约定在触摸屏上的方式)。知道您可以简单地创建一个 if 语句,然后只完成一次事件:

      bool _tempKeyPressedOnce = false;
      if (!_tempKeyPressedOnce) {
          // do stuff
          _tempKeyPressedOnce = true;
      }
      

      【讨论】:

      • 但是我如何访问RawKeyDownEvent 或任何我需要查看它是否只是按键或向上的东西,以便我可以在其上使用布尔值
      • 类似这样的东西:RawKeyDownEvent keyDownEvent = key; keyDownEvent.data;
      【解决方案6】:

      这是你可以让它工作的方法:

      RawKeyboardListener(
        focusNode: FocusNode(),
        onKey: (event) {
          // Only taking key down event into consideration
          if (event.runtimeType == RawKeyDownEvent) {
            bool shiftPressed = event.isShiftPressed; // true: if shift key is pressed
          }
        },
        child: TextField(),
      )
      

      【讨论】:

        【解决方案7】:

        RawKeyboardListener 小部件 每当用户按下或释放键盘上的键时调用回调的小部件。

        以下代码如何实现RawKeyboardListener

        首先处理来自RawKeyboardListener的关键事件并更新_message

        void _handleKeyEvent(RawKeyEvent event) {
          setState(() {
            if (event.logicalKey == LogicalKeyboardKey.keyQ) {
              _message = 'Pressed the "Q" key!';
            } else {
              if (kReleaseMode) {
                _message = 'Not a Q: Key label is "${event.logicalKey.keyLabel ?? '<none>'}"';
              } else {
                // This will only print useful information in debug mode.
                _message = 'Not a Q: Pressed ${event.logicalKey.debugName}';
              }
            }
          });
        }
        

        使用这种方法后

        @override
        Widget build(BuildContext context) {
          final TextTheme textTheme = Theme.of(context).textTheme;
          return Container(
            color: Colors.white,
            alignment: Alignment.center,
            child: DefaultTextStyle(
              style: textTheme.display1,
              child: RawKeyboardListener(
                focusNode: _focusNode,
                onKey: _handleKeyEvent,
                child: AnimatedBuilder(
                  animation: _focusNode,
                  builder: (BuildContext context, Widget child) {
                    if (!_focusNode.hasFocus) {
                      return GestureDetector(
                        onTap: () {
                          FocusScope.of(context).requestFocus(_focusNode);
                        },
                        child: const Text('Tap to focus'),
                      );
                    }
                    return Text(_message ?? 'Press a key');
                  },
                ),
              ),
            ),
          );
        }
        

        【讨论】:

          【解决方案8】:

          我使用这个函数从键盘写入值

                    handleKey(RawKeyEvent event) {
                      if (event is RawKeyDownEvent) {
                        if (event.physicalKey == PhysicalKeyboardKey.enter) {
                          log('ENTER');
                          _text = '';
                        } else {
                          log('Event data keyLabel ${event.data.keyLabel}');
                          _text += event.data.keyLabel;
                        }
                        log('text: $_text');
                      }
                    }
          

          它不会重复从键盘写入值

          【讨论】:

            猜你喜欢
            • 2020-10-28
            • 2022-11-28
            • 1970-01-01
            • 2021-11-05
            • 1970-01-01
            • 2020-03-05
            • 2021-09-20
            • 2023-02-15
            • 2019-11-01
            相关资源
            最近更新 更多