【Flutter】TextField 监听长按菜单粘贴点击事件

背景

因为项目需要,需要监听输入框长按出现上下文菜单粘贴(Paste)事件,Flutter中的输入框组件TextField并不能像Android原生中EditText原生View一样,重写onTextContextMenuItem回调方法一样简单的做到监听粘贴按钮的点击事件,而是需要自定义ContextMenu来实现。

实现

1. 根据TextField提供的EditableTextState创建自定义上下文菜单

dart 复制代码
class _CustomContextMenu extends StatelessWidget {
  final EditableTextState editableTextState;
  final VoidCallback onPaste;

  const _CustomContextMenu({required this.editableTextState, required this.onPaste});

  @override
  Widget build(BuildContext context) {
    final List<ContextMenuButtonItem> items = editableTextState.contextMenuButtonItems;

    // 创建新的菜单列表
    List<ContextMenuButtonItem> customItems = [];

    for (var item in items) {
      print('item: ${item}');
      if (item.type == ContextMenuButtonType.paste) {
        customItems.add(
          ContextMenuButtonItem(
            onPressed: () {
              if (item.onPressed != null) {
                item.onPressed!();
              }
              onPaste();
            },
            label: item.type.name,
            type: item.type,
          ),
        );
      } else {
        if (item.label?.isNotEmpty == true || item.type.name.isNotEmpty) {
          customItems.add(item);
        }
      }
    }

    return AdaptiveTextSelectionToolbar(
      anchors: editableTextState.contextMenuAnchors,
      children: customItems.map((item) {
        return TextButton(
          onPressed: item.onPressed,
          child: Text(item.label ?? item.type.name, style: TextStyle(color: Colors.black)),
        );
      }).toList(),
    );
  }
}

这其中最关键 的代码在判断ContextMenuButtonItem的类型,然后重新创建一个带有业务逻辑的全新的ContextMenuButtonItem。其他不需要自定义的ContextMenuButtonItem保持不变。

2. 将自定义_CustomContextMenu应用到TextField中

dart 复制代码
class _PasteListenerDemoState extends State<PasteListenerDemo> {
  final TextEditingController _controller = TextEditingController();
  final FocusNode _focusNode = FocusNode();
  final ValueNotifier<bool> _pasteClicked = ValueNotifier(false);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(20),
      child: Column(
        children: [
          TextField(
            controller: _controller,
            focusNode: _focusNode,
            decoration: InputDecoration(border: OutlineInputBorder(), labelText: "尝试长按粘贴"),
            contextMenuBuilder: (context, editableTextState) {
              return _CustomContextMenu(
                editableTextState: editableTextState,
                onPaste: () {
                  _pasteClicked.value = true;
                  Future.delayed(Duration(seconds: 2), () {
                    _pasteClicked.value = false;
                  });
                },
              );
            },
          ),
          SizedBox(height: 20),
          ValueListenableBuilder<bool>(
            valueListenable: _pasteClicked,
            builder: (context, value, child) {
              return Text(
                value ? "粘贴按钮被点击了!" : "等待粘贴操作...",
                style: TextStyle(fontSize: 18, color: value ? Colors.green : Colors.grey),
              );
            },
          ),
        ],
      ),
    );
  }
}
相关推荐
Sammyyyyy1 小时前
PHP 8.5 新特性:10 大核心改进
android·php·android studio
TO_ZRG1 小时前
Unity 通过 NativePlugin 接入Android SDK 指南
android·unity·游戏引擎
n***84072 小时前
Springboot-配置文件中敏感信息的加密:三种加密保护方法比较
android·前端·后端
方白羽3 小时前
一次由 by lazy 引发的“数据倒灌”,深入理解 `by`关键字、`lazy`函数的本质
android·kotlin·app
v***55343 小时前
MySQL 中如何进行 SQL 调优
android·sql·mysql
vx_vxbs665 小时前
【SSM高校普法系统】(免费领源码+演示录像)|可做计算机毕设Java、Python、PHP、小程序APP、C#、爬虫大数据、单片机、文案
android·java·python·mysql·小程序·php·idea
微:xsooop5 小时前
iOS 上架4.3a 审核4.3a 被拒4.3a 【灾难来袭】
flutter·unity·ios·uniapp
程序员老刘5 小时前
假如Flutter用Rust,你也写不出更快的App
flutter·rust·dart
j***82706 小时前
【MyBatisPlus】MyBatisPlus介绍与使用
android·前端·后端
ljt27249606616 小时前
Compose笔记(五十八)--LinearOutSlowInEasing
android·笔记·android jetpack