【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),
              );
            },
          ),
        ],
      ),
    );
  }
}
相关推荐
砖厂小工1 天前
用 GLM + OpenClaw 打造你的 AI PR Review Agent — 让龙虾帮你审代码
android·github
张拭心1 天前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心1 天前
Android 17 来了!新特性介绍与适配建议
android·前端
shankss1 天前
Flutter 下拉刷新库 pull_to_refresh_plus 设计与实现分析
flutter
Kapaseker1 天前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴1 天前
Android17 为什么重写 MessageQueue
android
忆江南2 天前
iOS 深度解析
flutter·ios
明君879972 天前
Flutter 实现 AI 聊天页面 —— 记一次 Markdown 数学公式显示的踩坑之旅
前端·flutter
恋猫de小郭2 天前
移动端开发稳了?AI 目前还无法取代客户端开发,小红书的论文告诉你数据
前端·flutter·ai编程
MakeZero2 天前
Flutter那些事-交互式组件
flutter