Android WebView 长按弹出的文本选择器如何监听滑动和如何弹出完全自定义的菜单栏

news2024/11/26 22:19:50

在这次改版中,h5小伙伴与我沟通说要把长按选择改用成原生的拉选框,之前我也没搞过呀,开始研究吧。

怎么研究呀,当然是百度一下了。

百度了一天总结如下:

好多文章都是告诉你如何在系统的基础上来修改自己的文字和点击事件。

要么就是与H5配合让H5小伙伴控制 拉选框,你来弹框(我们之前就是这样的)。

现在我要实现的是长按webview后弹出来的拉选框(就是两个可以滑动的图标、用来选择文字的)要用android系统自带的,然后弹出的菜单栏要我们android自己自定义的弹框(以前就是自定义,许多功能都是写好的,我们还有单击也会弹这个框)。

说那么多鬼知道你要实现什么啊,直接上截图!

就是这样的效果。

怎么实现呢,其实很简单呀,首先我们自定义webview,然后重写startActionMode方法

是的跟他们之前一样。上代码

 @Override
    public ActionMode startActionMode(ActionMode.Callback callback) {
        ActionMode actionMode = super.startActionMode(buildCustomCallback(callback));
        actionMode.getMenu().clear();
        return actionMode;
    }

    @Override
    public ActionMode startActionMode(ActionMode.Callback callback, int type) {
        ActionMode actionMode = super.startActionMode(buildCustomCallback(callback), type);
        actionMode.getMenu().clear();
        return actionMode;
    }

buildCustomCallback() 这个方法是干什么的呀,其实也没啥就是自定义了个 ActionMode.Callback

代码如下


    private ActionMode.Callback buildCustomCallback(final ActionMode.Callback callback) {

        return new ActionMode.Callback2() {
            @Override
            public boolean onCreateActionMode(ActionMode mode, Menu menu) {
                LogUtil.d(TAG, "buildCustomCallback onCreateActionMode");
                if (mode.getMenu() != null)
                    mode.getMenu().clear();
                return callback.onCreateActionMode(mode, menu);
            }

            @Override
            public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
                LogUtil.d(TAG, "buildCustomCallback onPrepareActionMode");
                callback.onPrepareActionMode(mode, menu);
                if (isFirst && textSelectedListener != null) {
                    textSelectedListener.OnTextSelected(markTop, markLeft);
                    markTop = 0;
                    markLeft = 0;
                }
                if (mode.getMenu() != null)
                    mode.getMenu().clear();
                return true;
            }

            @Override
            public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                LogUtil.d(TAG, "buildCustomCallback onActionItemClicked");
                if (item == null || TextUtils.isEmpty(item.getTitle())) {
                    return callback.onActionItemClicked(mode, item);
                }
                String title = item.getTitle().toString();
                return callback.onActionItemClicked(mode, item);
            }

            @Override
            public void onDestroyActionMode(ActionMode mode) {
                LogUtil.d(TAG, "buildCustomCallback onDestroyActionMode");
                if (mode != null)
                    mode.invalidate();
                callback.onDestroyActionMode(mode);
            }

            @Override
            public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
                int height = outRect.height();
                float exactY = outRect.exactCenterY();
                LogUtil.d(TAG, exactY + "   --- " + height + "  buildCustomCallback onGetContentRect:" + outRect.top + "    centerX:" + outRect.centerX());
                if (outRect.top != 0) {
                    isFirst = true;
                    markTop = outRect.top;
//                    markLeft = outRect.left > 0 ? outRect.left : 0;
                    markLeft = outRect.centerX();
                } else {
                    isFirst = false;
                }
                if (callback instanceof ActionMode.Callback2) {
                    ActionMode.Callback2 tempCallback2 = (ActionMode.Callback2) callback;
                    tempCallback2.onGetContentRect(mode, view, outRect);
                } else {
                    super.onGetContentRect(mode, view, outRect);
                }
            }
        };

    }

这里面有一个

 @Override
            public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
}

这里面的 outRect 非常重要因为我就是从这个地方获取的拉选框位置的,怎么获取呢很简单直接拿它的top和left就可以了呀。

研究了一天半终于实现这个功能了,确实不容易呀,然后就开始测试发现竟然有bug,就是位置竟然不对劲,比如我从第三行开始选择,我拉都第二行拉到第一行,看着对劲,然后再从第一行拉到第二行的时候竟然位置不对了,怎么回事!位置竟然跑到选择第一行的位置了,明明在第二行啊,又是一堆研究测试终于发现问题了,原来是因为他这个方法永远返回差了一行的位置!

找到问题该怎么解决啊,难道是系统bug???这咋弄

想尽脑汁也不知道该怎么处理,在网上各种搜索,偏偏关于webview长按文字选择这样的文章少的可怜,有也是几乎抄袭的就那么几篇。怎么办

于是我想着既然他一直少一行那么我手动让它给咱们刷新不就行了,我找一下看看有没有刷新方法,

  mode.invalidate();

没错就是这个方法,我们手动让ActionMode给咱们刷新不就好了,于是我就测试先放在了 onGetContentRect ,一运行直接卡死了,哈哈,于是又想放到onDestroyActionMode比较好,测试跑起来没问题!搞定了,可以愉快的玩耍了!

demo没写 代码直接从项目中拿出来的,要是有小伙伴看不懂,留言我去写个demo放到git上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/513416.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vue2 框架运行原理剖析系列(二)之 组件挂载$mount神秘之旅!!!

一、vue组件挂载 1.1 上一篇文章中,介绍到组件执行 mountComponent 函数,本文对此展开详细的讲解。 1.2 调用改方法的位置在于entry-runtime-with-compiler.js 的Vue.prototype.$mount,具体代码如下: 其中, &#xff…

【图像融合】Dif-Fusion:基于扩散模型的红外/可见图像融合方法

文章目录 摘要一、前言二、相关工作1.红外线和可见光的图像融合2.扩散模型(可见博主之前的博客) 三、方法1.红外线和可见光图像的联合扩散2*.多通道扩散特征的融合 四、实验1.实验设置2.融合性能分析(效果展示)3.泛化实验 总结 摘…

通知短信 API 技术细节以及发送流程机制原理解析

引言 短信是一种简单、直接、高效的通信方式,被广泛应用于各个领域。在移动互联网时代,短信成为了客户服务、政府通知、公共服务等方面的重要工具。为了更好地利用短信这种通信方式,通知短信 API应运而生。短信API可以帮助企业、政府和应用程…

RK3588旗舰32T人工智能多网口边缘智能网关交换机

32T边缘智能网关发布,助力多行业数字化升级,运维降本增效,搭载RK3588旗舰芯 搭载瑞芯微RK3588芯片的边缘智能网关XM-RK3588,算力可扩展至32T,适用于电力能源、智慧交通、智慧城市、智慧安防、智慧医疗、工业互联网等领…

前端的加密和解密,crypto-js的应用,AES / RSA / md5

每日鸡汤:每个你想学习的瞬间,都是未来你的向自己求救 内容预警*****新手内容,自己学习总结用****大佬请绕道 之前看https原理,看到对称加密和非对称加密,各种加密方法,看得云里雾里,即便是总结…

报错main.py: error: unrecognized arguments: stack_size 4 1001,770,123

运行从GitHub上面下载下来的代码时,按照作者提供的输入命令输入后报错: main.py: error: unrecognized arguments: stack_size 4 1001,770,123 将报错的部分在网上百度,找到部分方法,得出理解:输入的命令是出错的&am…

【RS专题】怎么知道你遇到的是rs风控

本文属于技术分享、如有侵权可联系本人下架 最简单的方法就是查看cookie,在控制台输入【document.cookie】 如果出现如上图中有【xxxxxxT】或者【xxxxxxP】的,并且它的值都为英文数字和下滑线加点,那么基本可以确定这个网站用了rs反爬 什么是rs反爬,下面抄一段内容 瑞数动…

【瑞数RS专题】首层代码分析,和获取eval层代码,cookie反爬虫详解

如有侵权、联系本人下架 以下面两个网站为例 1.aHR0cDovL3d3dy5mYW5nZGkuY29tLmNuL25ld19ob3VzZS9uZXdfaG91c2VfZGV0YWlsLmh0bWw= 2.aHR0cHM6Ly93d3cubm1wYS5nb3YuY24veWFvd2VuL3lwamd5dy9pbmRleC5odG1s 首先明确一下目标,我们要先获取网页200的源代码,RS5代第一次响应为…

unittest自动化测试框架讲解以及实战

为什么要学习unittest 按照测试阶段来划分,可以将测试分为单元测试、集成测试、系统测试和验收测试。单元测试是指对软件中的最小可测试单元在与程序其他部分相隔离的情况下进行检查和验证的工作,通常指函数或者类,一般是开发完成的。 单元…

软件架构:软件架构设计的三个维度

架构设计是一个非常大的话题,不管写几篇文章,接触到的始终只是冰山一角,更多的是实践中去体会。这篇文章主要介绍面向对象OO、面向方面AOP和面向服务SOA这三个要素在架构设计中的位置与作用。   架构设计有三个维度,或者说是我们…

文案改写神器软件-文案改编神器

文案改写神器软件 文案改写神器软件通常致力于通过人工智能技术将一篇已有文案进行改写和改编,以达到复用或优化的目的。以下是文案改写神器软件通常可以做的事情: 改写原文:文案改写神器可以通过自定义规则、语法分析和文本相似性匹配等功能…

设计模式之【组合模式】,树形结构的完美解决方案

文章目录 一、什么是组合模式1、组合模式三大角色2、组合模式应用场景3、组合模式注意事项和细节 二、透明组合模式1、学院院系案例2、透明组合模式总结 三、安全组合模式1、linux目录系统案例2、安全组合模式总结 四、源码中使用的组合模式1、HashMap2、ArrayList3、MyBatis 一…

跨平台应用开发进阶(六十一):uni-app 跨平台技术开发框架可行性调研

文章目录 一、流程类二、研发类(uni-app框架)三、心得分享(研发踩坑&uni-app踩坑)四、拓展阅读 一、流程类 IOS和安卓企业开发者账户申请流程(申请渠道、需要提供的相关证明、审核时间等)。 答:uni-app使用HBuliderX作为开发IDE,支持邮箱、密码方式注册&#x…

95、Image Restoration with Mean-Reverting Stochastic Differential Equations

简介 主页:https://github.com/Algolzw/image-restoration-sde 扩散模型终于在去噪、超分辨率等应用了。 这是一种基于随机微分方程的通用图像恢复方法,关键结构包括均值还原SDE,该SDE将高质量图像转换为具有固定高斯噪声的平均状态的降级…

怎么压缩png图片的大小?4个简单高效工具分享

怎么压缩png图片的大小?大家都知道jpg和png是目前电脑上最主流的两大图片文件格式,jpg图片的体积比较小,因为它属于有损压缩的图片格式,而png图片的体积相对就要大很多了,因为png属于无损压缩的图片格式。大家也同样知…

Redission实现分布式锁之源码解析

Redission实现分布式锁之源码解析 1、Redission实现分布式锁之源码解析1.1 分布式锁-redission功能介绍1.2 分布式锁-Redission快速入门1.3 分布式锁-redission可重入锁原理1.4 分布式锁-redission锁重试和WatchDog机制1.5 分布式锁-redission锁的MutiLock原理 1、Redission实现…

5G+工业互联网观察——应用篇

5G与工业互联网的结合是5G应用的重要领域,前一篇《5G工业互联网观察——政策篇》我们对5G工业互联网的相关政策进行了整理和分析,本篇继续从应用的角度整理目前的典型场景和重点行业,并进行简单的分析。 文 | 无界 全文4500字,预计…

原创 | 一文读懂蒙特卡洛算法

作者:陈之炎本文约2000字,建议阅读10分钟 本文介绍了蒙特卡洛算法。 蒙特卡洛算法(Monte Carlo algorithm)是一种基于随机采样的计算方法,其基本思想是通过生成随机样本,利用统计学原理来估计数学问题的解。…

MySQL实战之主从数据同步机制

主从同步的重要性: 解决数据可靠性的问题需要用到主从同步;解决 MySQL 服务高可用要用到主从同步;应对高并发的时候,还是要用到主从同步。 一、MySQL 主从同步流程 当客户端提交一个事务到 MySQL 的集群,直到客户端收…

《JavaEE初阶》Servlet

《JavaEE初阶》Servlet 文章目录 《JavaEE初阶》Servlet编写一个Servlet的helloworld1. 认识Maven并创建maven项目:2. 引入依赖:3.创建目录:4. 编写代码:5. 打包6. 部署7.验证 优化打包部署操作.常见的错误: ServletAPI:利用ajax构造请求.使用第三方工具postman构造请求HttpSer…