flutter 效果实现 —— 键盘快捷键绑定

对于快捷键绑定回调大致有三种方式,第一种是使用 CallbackShortcuts;第二种是使用 Focus 的 onKey 回调,参考前一篇文章中的 Key Events 的示例1;第三种就是下面所介绍的。

效果:

代码:

class ShortcutPage extends StatefulWidget {
  ShortcutPage({super.key});

  @override
  State<ShortcutPage> createState() => _ShortcutPageState();
}

class _ShortcutPageState extends State<ShortcutPage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Shortcuts.manager(
        // return Shortcuts(
        //   shortcuts: <LogicalKeySet, Intent>{
        //     LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyA): const SelectAllIntent(),
        //   },
        manager: LoggingShortcutManager(
            // ① 快捷方式与 Intent 的映射
            shortcuts: <LogicalKeySet, Intent>{
              LogicalKeySet(LogicalKeyboardKey.control, LogicalKeyboardKey.keyU): const ClearIntent(),
            }),
        child: Column(
          children: [
            Expanded(child: ClearTextField(title: "Shortcuts and Actions Demo")),
            Expanded(child: TextSelectionField()),
          ],
        ),
      ),
    );
  }
}

/// 文本清除组件
class ClearTextField extends StatefulWidget {
  const ClearTextField({super.key, required this.title});

  final String title;

  @override
  State<ClearTextField> createState() => _ClearTextFieldState();
}

class _ClearTextFieldState extends State<ClearTextField> {
  late TextEditingController controller = TextEditingController();

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Actions(
      dispatcher: LoggingActionDispatcher(),
      //② Intent 与 Action 的映射
      actions: <Type, Action<Intent>>{
        ClearIntent: ClearAction(controller),
      },
      child: Builder(builder: (context) {
        return Row(
          children: <Widget>[
            const Spacer(),
            Expanded(
              child: TextField(controller: controller),
            ),
            IconButton(
              icon: const Icon(Icons.clear),
              onPressed: Actions.handler<ClearIntent>(context, const ClearIntent()),
            ),
            const Spacer(),
          ],
        );
      }),
    );
  }
}

//③ 一个Intent 子类,用于联系 Shortcut 与 Action
class ClearIntent extends Intent {
  const ClearIntent();
}

//④ Action 快捷键按下后所执行的操作,除了继承 Action,还可以使用 CallbackAction
class ClearAction extends Action<ClearIntent> {
  ClearAction(this.controller);

  final TextEditingController controller;

  @override
  Object? invoke(covariant ClearIntent intent) {
controller.clear();
    return null;
  }
}

/// Action分发日志
class LoggingActionDispatcher extends ActionDispatcher {
  @override
  Object? invokeAction(
    covariant Action<Intent> action,
    covariant Intent intent, [
    BuildContext? context,
  ]) {
    print('Action invoked: $action($intent) from $context');
    super.invokeAction(action, intent, context);

    return null;
  }
}

/// 快捷方式管理(添加日志)
class LoggingShortcutManager extends ShortcutManager {
  LoggingShortcutManager({super.shortcuts});

  @override
  KeyEventResult handleKeypress(BuildContext context, RawKeyEvent event) {
    final KeyEventResult result = super.handleKeypress(context, event);
    if (result == KeyEventResult.handled) {
      print('Handled shortcut $event in $context');
    }
    return result;
  }
}


/// 文本全选组件
class TextSelectionField extends StatefulWidget {
  const TextSelectionField({Key? key}) : super(key: key);

  @override
  State<TextSelectionField> createState() => _TextSelectionFieldState();
}

class _TextSelectionFieldState extends State<TextSelectionField> {
  final TextEditingController _controller = TextEditingController();
  final FocusNode _focusNode = FocusNode();
  @override
  void dispose() {
    _controller.dispose();
    _focusNode.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onDoubleTap: () {
        _controller.selection = TextSelection(baseOffset: 0, extentOffset: _controller.value.text.length);
      },
      child: Row(
        children: <Widget>[
          const Spacer(),
          Expanded(
            child: TextField(controller: _controller, focusNode: _focusNode,),
          ),
          IconButton(
              icon: const Icon(Icons.select_all),
              onPressed: () {
                //按下按钮时,焦点转移到按钮自身,因此这里需要手动将焦点移动到原来的输入框
                _focusNode.requestFocus();
                // _controller.selection = TextSelection(baseOffset: 0, extentOffset: _controller.value.text.length);
                _controller.selection = _controller.selection.copyWith(
                  baseOffset: 0,
                  extentOffset: _controller.text.length,
                  affinity: _controller.selection.affinity,
                );
              }
          ),
          const Spacer(),
        ],
      ),
    );
  }
}

posted on 2022-09-21 00:38  Lemo_wd  阅读(502)  评论(0编辑  收藏  举报

导航