【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),
              );
            },
          ),
        ],
      ),
    );
  }
}
相关推荐
summerkissyou198717 分钟前
Android-MediaSession-播放流程和例子
android·mediasession
李李李勃谦1 小时前
Flutter 框架跨平台鸿蒙开发 - 星空日记
flutter·华为·harmonyos
2401_839633911 小时前
鸿蒙flutter第三方库适配 - 看板应用
flutter·华为·harmonyos
私人珍藏库1 小时前
[Android] 蓝叠模拟器工具箱v1.1
android·智能手机·app·工具·软件·多功能
空中海2 小时前
5.1 HTTP 与网络请求
网络·网络协议·flutter·http
云霄IT3 小时前
安卓开发之java转dex再转smali
android·java·python
提子拌饭1333 小时前
生命组学架构下的细胞分化与基因突变生存模拟器:基于鸿蒙Flutter的情景树渲染与状态溢出防御
flutter·华为·架构·开源·harmonyos
XiaoLeisj4 小时前
Android 短视频项目实战:从用户中心页与沉浸式登录,到验证码鉴权、用户信息持久化和 EventBus 登录态同步
android·webview·eventbus·countdowntimer·token 加密·键值对存储 sp·封装toast/加载 ui
空中海5 小时前
6.1 主题与暗色模式
运维·服务器·前端·flutter
JJay.5 小时前
Android BLE 扫描连接与收发消息实战
android