WebView 自定義長按選擇,實現收藏 / 分享選中文字。

戀貓de小郭發表於2019-03-04

Hello,大家吼,吾就是那個挖坑不止的郭小喵,不管有沒有想我(˶‾᷄ ⁻̫ ‾᷅˵)的,這次就分享快速實現一個自定義WebView的小控制元件吧,效果如下圖,廢話不多說,我們直接開擼吧。

(PS : ╮(╯▽╰)╭如果你翻一翻我過去的文章,你會發現90%的開場白,前幾個問候語都是一樣的。)

WebView 自定義長按選擇,實現收藏 / 分享選中文字。
效果圖(1.3M)

一、前言

** 戳這裡可以去DEMO,來吧 **

相信剛接觸android不久的同志們,在面對產品提出的 :

 “自定義WebView頁面中,長按文字的彈出選項、點選選擇後,分享、轉發、收藏選擇文字”複製程式碼

這樣的需求時,第一反應大部分是:這是系統行為,如果實現需要在web端實現。

 但是web端實現的侷限性太大,曾經也有過監聽系統貼上板,在使用者點選複製的時候實現其他的邏輯,但是這樣使用者體驗不好,所以自定義WebView中長按的彈出選單,並在點選時返回選中文字的小控制元件閃亮登場┏ (^ω^)=。

二、自定義長按彈出選單

 這一步實現其實很簡單,首先建立一個CustomActionWebView繼承系統WebView,然後重寫下面兩個方法。

 這兩個方法會在使用者長按選擇web文字時,在彈出選單前被呼叫。它們之間的區別在於,第一個方法的選單彈出方式,指定了預設的type。我們並不關係彈出的item型別是什麼,我們只需要攔截下來ActionMode,然後返回我們自己的自定義ActionMode即可。

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

@Override
public ActionMode startActionMode(ActionMode.Callback callback, int type) 
    ActionMode actionMode =  super.startActionMode(callback, type);
    return resolveActionMode(actionMode);
}複製程式碼

這裡我們所做的事是:

  • 1、把原本的actionMode物件儲存到mActionMode中。
  • 2、清空原本actionMode中的MenuItem。
  • 3、新增我們自定義的item到actionMode中。
  • 4、重定義每個menuItem的點選事件。
  • 5、在點選事件中通過執行js,獲取選中文字。
  • 6、通過上面儲存的 mActionMode,釋放彈出選單(不釋放會記憶體洩漏)。
  • 7、返回新填充的actionMode給系統。

/**
 * 處理item,處理點選
 * @param actionMode
 */
private ActionMode resolveActionMode(ActionMode actionMode) {
    if (actionMode != null) {
        final Menu menu = actionMode.getMenu();
        mActionMode = actionMode;
        menu.clear();
        for (int i = 0; i < mActionList.size(); i++) {
            menu.add(mActionList.get(i));
        }
        for (int i = 0; i < menu.size(); i++) {
            MenuItem menuItem = menu.getItem(i);
            menuItem.setOnMenuItemClickListener(new Item.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    getSelectedData((String) item.getTitle());
                    releaseAction();
                    return true;
                }
            });
        }
    }
    mActionMode = actionMode;
    return actionMode;
}複製程式碼

WebView 自定義長按選擇,實現收藏 / 分享選中文字。
實現效果

三、獲取選中文字

 光自定義選單,拿不到選中文字也沒意義,那麼如何獲取選中文字呢?這裡如果不轉個彎,還真會在南牆在撞死( ̄^ ̄)ゞ,所以,我們偉大的js就出現了。

 首先,我們自定義一個介面,用於監聽js方法,其中@JavascriptInterface是關鍵的所在, 在callback中獲取js端返回的資料

 然後將這個介面,在CustomActionWebView中add進去(一般是在初始化和頁面載入完成時都add一次),並指定js端呼叫的介面名稱為“ JSInterface”。(ps:別忘了開始webview的js允許哦。)

public void linkJSInterface() {
   addJavascriptInterface(new ActionSelectInterface(this), "JSInterface");
}

···

/**
 * js選中的回撥介面
 */
private class ActionSelectInterface {

    CustomActionWebView mContext;

    ActionSelectInterface(CustomActionWebView c) {
        mContext = c;
    }

    @JavascriptInterface
    public void callback(final String value, final String title) {
        if(mActionSelectListener != null) {
            mActionSelectListener.onClick(title, value);
        }
    }
}複製程式碼

 最後在點選時,通過執行js來獲取web中選中的文字。在上面自定義選單中第5項,點選menu時,執行下方js程式碼,便可以把選中的item和文字,回撥到上面的介面中的callback。

熟悉js的小夥伴已經看出來吧:

  • 其實就是定義了一個js的function,然後在webview中執行這個方法。
  • 定義的這個名為function getSelectedText()的js方法,有兩個變數:txt和title。
  • title是從原生中傳入的item名字,txt是通過window去獲取web中選中的文字。
  • 最後回到上面我們註冊的js方法名JSInterface,通過它的callback方法,將文字和name返回到原生程式碼callback中。
  • 根據版本不同,執行js方法的介面也不一樣。
/**
 * 點選的時候,獲取網頁中選擇的文字,回掉到原生中的js介面
 * @param title 傳入點選的item文字,一起通過js返回給原生介面
 */
private void getSelectedData(String title) {

    String js = "(function getSelectedText() {" +
            "var txt;" +
            "var title = \"" + title + "\";" +
            "if (window.getSelection) {" +
            "txt = window.getSelection().toString();" +
            "} else if (window.document.getSelection) {" +
            "txt = window.document.getSelection().toString();" +
            "} else if (window.document.selection) {" +
            "txt = window.document.selection.createRange().text;" +
            "}" +
            "JSInterface.callback(txt,title);" +
            "})()";
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        evaluateJavascript("javascript:" + js, null);
    } else {
        loadUrl("javascript:" + js);
    }
}複製程式碼

WebView 自定義長按選擇,實現收藏 / 分享選中文字。

四、最後

 既然自定義item實現了,點選和選擇文字返回也實現了,在callback中,你就可以愉悅的收藏,或者分享你所選中的文字啦(◐‿◑),操作一氣呵成,有沒有被驚豔到呢?

 如果感興趣的,可以下載demo看下,同時CustomActionWebView也封裝好了遠端依賴,歡迎使用。

github.com/CarGuo/Cust…

WebView 自定義長按選擇,實現收藏 / 分享選中文字。
寫文章也是個累活

相關文章