android WebView 长按自由复制文字,进入文字选择模式

长按WebView系统默认进入文字选择默认,但如果想实现先长按菜单显示菜单同能菜单选项来判断是否进行的进入自由复制文本文字选择的操作就不知道该怎么办了。

长按WebView显示弹出菜单,可怎么才在能实现点击菜单选择进入自由复制文本模式呢?在网上翻了个遍,都不怎么如意,纠结了几日,下午偷懒睡了一觉突然就想到了Instrumentation模拟长按操作触发WebView默认的显示复制菜单


先实现模拟长按操作实现类

/**
 * 模拟点击事件和长按事件
 *
 */

public class TouchEventRunnable implements Runnable {
    private int x;
    private int y;

    private boolean isLongPress;

    public TouchEventRunnable(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public TouchEventRunnable(int x, int y, boolean isLongPress) {
        this.x = x;
        this.y = y;
        this.isLongPress = isLongPress;
    }

    @Override
    public void run() {
        if(isLongPress){
            longClickOnScreen(x,y);
        }else{
            onClick();
        }
    }


    private void longClickOnScreen(int x, int y) {
        final Instrumentation inst = new Instrumentation();
        try {
            long downTime = SystemClock.uptimeMillis();
            long eventTime = SystemClock.uptimeMillis();
            final MotionEvent eventDown = MotionEvent.obtain(downTime,
                    eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
            eventDown.setSource(InputDevice.SOURCE_TOUCHSCREEN);
            final MotionEvent eventMove = MotionEvent.obtain(downTime, eventTime,
                    MotionEvent.ACTION_MOVE, x, y+1, 0);
            eventMove.setSource(InputDevice.SOURCE_TOUCHSCREEN);
            final MotionEvent eventUp = MotionEvent.obtain(downTime, eventTime,
                    MotionEvent.ACTION_UP, x, y, 0);
            eventUp.setSource(InputDevice.SOURCE_TOUCHSCREEN);
            inst.sendPointerSync(eventDown);
            inst.sendPointerSync(eventMove);
            try {
                Thread.sleep(650);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            inst.sendPointerSync(eventUp);
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }



    private void onClick(){

        Instrumentation inst = new Instrumentation();
        inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_DOWN, x, y, 0));
        inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
                MotionEvent.ACTION_UP, x, y, 0));
        //Log.v("LOG", " x = " + x + " y = " + y);

    }
}

接下来是长按WebView先要显示的菜单代码


 public void showMenu(View v){
        Activity mContext = this;
        android.app.FragmentTransaction mFragTransaction = mContext.getFragmentManager().beginTransaction();
        android.app.Fragment fragment =  mContext.getFragmentManager().findFragmentByTag("dialogFragment");
        if(fragment!=null){
            mFragTransaction.remove(fragment);
        }

        ListDialogFragment dialogFragment = ListDialogFragment.newInstance("bookmarkFragment");
        dialogFragment.setWidthPercent(0.38f,0.38f);


        focusedRawPosition = ((WebViewCopyText) v).getTouchLocation();
        dialogFragment.optimzeLocation(v,focusedRawPosition);

        dialogFragment.setGravityAndXY(Gravity.LEFT|Gravity.TOP, focusedRawPosition[0],focusedRawPosition[1]);
        String[] menuStrs = new String[]{"自由复制","复制连接","分享网页"};
        dialogFragment.setListData(menuStrs);
        dialogFragment.setIsEnaledGravityAndXY(true);
        dialogFragment.setOnListDialogItemClickListener(new ListDialogFragment.OnListDialogItemClickListener() {
            @Override
            public void onClick(int position) {
                webView.getHandler().postDelayed(new Runnable() {
                    @Override
                    public void run() {

                        //先清空长按监听避免再次显示菜单,再听定时回调设置回来
                        webView.setOnLongClickListener(null);

                        //执行点击事件
                        new Thread(new TouchEventRunnable(focusedRawPosition[0],focusedRawPosition[1]+getStateBarHeight(),true)).start();

                        webView.getHandler().postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                webView.setOnLongClickListener(onLongClickListener);

                            }
                        },2500);

                    }
                },100);

            }
        });


        dialogFragment.show(mFragTransaction, "dialogFragment");//显示


    }

上面的代码主要是实现模拟长按操作进入自由复制文字选择模式。

但问题又来了,实际操作发现不管是模拟触发的还是WebView默认的,在同一个网页中有时可以进入文字选择默认,有时则不能,甚至有的网页怎么也无法进入。

通过浏览器调试,发现能进入复制文字选择魔的往往是HTML的h1~h6,span,p之类的元素,凡是长按a元素没有一个网页能进入自由复制模式的,再次对a原始的各个属性进行排查问题出在a元素的href属性上。

排查的结果是:

当HTML上的a元素设置了href属性时无法无法进入自由复制模式,但当a元素没有设置设置href属性时,则可以进入。

这下好了,用js的方法element.removeAttribute('href');把HTML上的所有的a元素的href属性移除掉,又可以进文字选择模式了。

至于为什么会是这样水平有限,无法深入研究。
下面是js移除href属性的代码.

/**
开始选择文字是去除a标签的href属性
**/
function startSelectText(){
    var ass = document.getElementsByTagName('a');

    for(var i = 0; i < arr.length; i++){
        var tag = arr[i];
        if(tag != null && tag.tagName != null){
            tag = tag.tagName.toLocaleLowerCase();
             if(tag != null &&  tag == 'a'){

                 var ele = arr[i];
                 var hed = ele.href;
                 if(hed){
                     var aHref = hed.value;
                     ele.removeAttribute('href');
                     ele.setAttribute('copyhref',aHref);
                 }
             }
         }
    }

}

实现的效果如下




这是Demo下载地址:去下载demo


下面是补充重要补充

      经过最近使用,该方法在部分网站失效,如访问https://portal.3g.qq.com/就无法正常。又经过排查。


android WebView 长按自由复制文字,进入文字选择模式_第1张图片





手机腾讯css的body元素设置了

-webkit-user-select:none;的属性值。禁止了复制文字功能。我们可以通过WebView的加载-webkit-user-select属性值,
设置为text的css文件,并结合上面的方法就又可以愉快的玩耍了。

下面是css代码

* html,body,a,img,textarea{
-webkit-touch-callout:text !important;
-webkit-user-select:text !important;
user-select:text !important;
}



ps:主要的代码就是这些,我能掌握的就只有这些,如果大神有什么好的方法,也请在下面留言,让我也跟着进步,谢谢。




你可能感兴趣的:(Android应用开发)