在桌面端开发中,键盘的交互在所难免。Flutter 框架中有 KeyboardListener 和 CallbackShortcuts 组件,可以让开发者非常方便地 监听键盘事件
以及 处理组合快捷键
。本文就来介绍这哥俩,其中案例的代码已经收录到了FlutterUnit 中,可以在对应组件中详细查看。
1. KeyboardListener 组件
FlutterUnit 中的案例很好地说明了 KeyboardListener
组件的功能。该组件需要提供 focusNode
参数用于焦点控制,获取焦点后就可以通过 onKeyEvent
回调监听按键事件:
事件会回调 KeyEvent
对象,他有三种类 KeyDownEvent(按下)、KeyUpEvent(抬起)、KeyRepeatEvent (重复)。上图中每次事件触发会渲染一个盒子,这三个事件类型分别对应 蓝色、灰色、绿色的盒子。
使用方式很简单,只需要将 KeyboardListener 套在目标组件之上,传入 focusNode
控制焦点,就可以通过 onKeyEvent
监听事件了。KeyEvent 中的 logicalKey 可以通过与 LogicalKeyboardKey
中的静态成员比较,得到用户按下的键位:
FocusNode focusNode = FocusNode();
KeyboardListener(
autofocus: true,
focusNode: focusNode,
onKeyEvent: _onKeyEvent,
child: _buildDisplay(),
),
void _onKeyEvent(KeyEvent value) {
print('${value.runtimeType}:${value.logicalKey.keyLabel}');
if (value.logicalKey == LogicalKeyboardKey.control) {
// ctrl 键事件
}
}
2.CallbackShortcuts 组件
相比于监听键盘按键,在桌面端中直接使用快捷键组合,这种场景更为常见。Flutter 框架中提供了 Shortcuts 组件处理键盘快捷键功能,在之前的 这篇介绍过。这里介绍一下 CallbackShortcuts 组件,它可以更便捷地使用快捷键:
如下面的案例中, 对于计数器的操作有三种快捷键操作: Ctrl+↑ 和 Ctrl+↓ 组合键可以增加或减少数字, Ctrl + R 将数值归零:
从源码中可以看出 CallbackShortcuts 在构造时除了 key 和 child 子组件外,最重要的是 bindings 入参:它是一个 快捷键和无参回调 的映射表,记录哪些组合键,对应的逻辑行为:
ShortcutActivator 抽象类有四个实现类:
如果是单个按键可以使用 SingleActivator
,它在构造时可以传入如下的bool 值,表示和常用按键组合。比如这里的 Ctrl + R 归零,用 SingleActivator(LogicalKeyboardKey.keyR, control: true) 即可。
LogicalKeySet 可以组合最多四个按键,在构造时依次传入即可:
在代码中使用时,通过如下的 _initActionBindings
方法创建组合键和对应函数的映射关系 _actionBindings
。可以在状态类 initState 回调中触发该初始方法,在 build 中将 _actionBindings
作为入参,构建 CallbackShortcuts 组件即可。
Map<ShortcutActivator, VoidCallback> _actionBindings = {};
void _initActionBindings() {
_actionBindings = {
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.arrowUp): increase,
LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.arrowDown): decrease,
const SingleActivator(LogicalKeyboardKey.keyR, control: true): reset,
};
}
void increase() {
setState(() => count = count + 1);
}
void decrease() {
setState(() => count = count - 1);
}
void reset() {
setState(() => count = 0);
}
总的来看,KeyboardListener 和 CallbackShortcuts 两个组件的用法还是非常简单的。下面我们来瞄一眼它们的源码实现。
3. 源码实现简看
KeyboardListener 组件的源码非常简单,他就是对 Focus 组件的简单封装,监听 Focus#onKeyEvent 事件,传递给外界。构造函数中传入的属性,也都是为构建 Focus 组件准备的:
而 CallbackShortcuts 组件也是对 Focus 组件的简单封装。也就是说 KeyboardListener 和 CallbackShortcuts 本质上是一个东西。只不过 CallbackShortcuts 对 Focus#onKeyEvent 事件进行了处理,只在组合按键的时机回调而已:
如何监听组合按键,源码中给出了非常明确的方案,在 _applyKeyEventBinding
函数中,通过 ShortcutActivator
对象的 accepts
方法,就可以检测事件是否是当前快捷键组合。如何是,就从映射关系中取回调函数触发:
onKeyEvent: (FocusNode node, KeyEvent event) {
KeyEventResult result = KeyEventResult.ignored;
// Activates all key bindings that match, returns "handled" if any handle it.
for (final ShortcutActivator activator in bindings.keys) {
result = _applyKeyEventBinding(activator, event) ? KeyEventResult.handled : result;
}
return result;
},
bool _applyKeyEventBinding(ShortcutActivator activator, KeyEvent event) {
if (activator.accepts(event, HardwareKeyboard.instance)) {
bindings[activator]!.call();
return true;
}
return false;
}
accepts 方法是 ShortcutActivator 类的抽象方法,每个子类有其具体的实现,比如下面是 SingleActivator 的实现:
尾声
总的来看,KeyboardListener 和 CallbackShortcuts 功能性很强,使用起来也很简单那。并且都是基于 Focus 组件实现功能的。至于 Focus 组件是什么,底层是如何实现的,后续会继续跟进,敬请期待~
更多文章和视频知识资讯,大家可以关注我的公众号、掘金和 B 站 。