1. 程式人生 > >android WebView 長按自由複製文字,進入文字選擇模式

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下載地址:

下面是補充重要補充

      經過最近使用,該方法在部分網站失效,如訪問https://portal.3g.qq.com/就無法正常。又經過排查。



手機騰訊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:主要的程式碼就是這些,我能掌握的就只有這些,如果大神有什麼好的方法,也請在下面留言,讓我也跟著進步,謝謝。