自定义长按文字弹出的菜单

长按 WebView 中的文字,会有抉择光标,并且弹出一个小菜单。 个别菜单里会有「复制」,「搜寻」等等选项。

这个菜单能够由开发者自定义。让弹出的菜单显示其余选项。 比方弹出「复制」「翻译」。

个别步骤:

  • 设计监听器
  • 自定义WebView,复写办法
  • 定义Js接口

须要新建2个 Java 文件,WebChooseActionListenerCustomClickWebView

定义监听器

监听器 WebChooseActionListener,用来传输用户的抉择。

public interface WebChooseActionListener {    /**     * @param itemTitle 选项的题目     * @param txt       选中的文字     */    void onChosen(String itemTitle, String txt);}

txt是用户在 WebView上选中的文字。如何获取到选中的文字呢? 本例中用 js 办法来获取。

自定义 WebView

js 和 Java 的交互

定义 CustomJsInterface (本例中把它放在了 CustomClickWebView 里),其中给 chooseAction 增加注解 @JavascriptInterface,将其定义为沟通的桥梁。 js中会调用这个 chooseAction 办法。

为了获取用户在 WebView 上选中的文字,须要执行 js 代码,参考exeSelectTextJs 办法。 js代码中的RFJSInterface,和Java中addJavascriptInterface传入的名字必须统一。

addJavascriptInterface(new CustomJsInterface(this), "RFJSInterface");

js代码中"RFJSInterface.chooseAction(txt,title);"就是在调用Java中定义的办法。

管制菜单

想要管制 WebView 中弹出的菜单,须要复写 startActionMode 办法,把默认的菜单替换成自定义的菜单。调用 Menu.add() 办法增加选项。

自定义的菜单选项,从里面传进来。

@Overridepublic ActionMode startActionMode(ActionMode.Callback callback) {    ActionMode actionMode = super.startActionMode(callback);    return resolveActionMode(actionMode);}@Overridepublic ActionMode startActionMode(ActionMode.Callback callback, int type) {    ActionMode actionMode = super.startActionMode(callback, type);    return resolveActionMode(actionMode);}private ActionMode resolveActionMode(ActionMode actionMode) {    if (actionMode != null) {        final Menu menu = actionMode.getMenu();        mCurActionMode = actionMode;        menu.clear();        for (int i = 0; i < mMenuItemNameList.size(); i++) {            menu.add(mMenuItemNameList.get(i));        }        for (int i = 0; i < menu.size(); i++) {            MenuItem menuItem = menu.getItem(i);            menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {                @Override                public boolean onMenuItemClick(MenuItem item) {                    exeSelectTextJs((String) item.getTitle());                    releaseAction();                    return true;                }            });        }    }    mCurActionMode = actionMode;    return actionMode;}

CustomClickWebView 代码:

import android.content.Context;import android.util.AttributeSet;import android.view.ActionMode;import android.view.Menu;import android.view.MenuItem;import android.webkit.JavascriptInterface;import android.webkit.WebView;import java.util.ArrayList;import java.util.List;public class CustomClickWebView extends WebView {    private ActionMode mCurActionMode;    private List<String> mMenuItemNameList = new ArrayList<>();    private WebChooseActionListener mWebChooseActionListener;    public CustomClickWebView(Context context) {        super(context);    }    public CustomClickWebView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public CustomClickWebView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);    }    @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);    }    private ActionMode resolveActionMode(ActionMode actionMode) {        if (actionMode != null) {            final Menu menu = actionMode.getMenu();            mCurActionMode = actionMode;            menu.clear();            for (int i = 0; i < mMenuItemNameList.size(); i++) {                menu.add(mMenuItemNameList.get(i));            }            for (int i = 0; i < menu.size(); i++) {                MenuItem menuItem = menu.getItem(i);                menuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {                    @Override                    public boolean onMenuItemClick(MenuItem item) {                        exeSelectTextJs((String) item.getTitle());                        releaseAction();                        return true;                    }                });            }        }        mCurActionMode = actionMode;        return actionMode;    }    private void releaseAction() {        if (mCurActionMode != null) {            mCurActionMode.finish();            mCurActionMode = null;        }    }    private void exeSelectTextJs(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;" +                "}" +                "RFJSInterface.chooseAction(txt,title);" +                "})()";        evaluateJavascript("javascript:" + js, null);    }    /**     * 在内部调用     */    public void linkJSInterface() {        addJavascriptInterface(new CustomJsInterface(this), "RFJSInterface");    }    /**     * @param actionList 弹出菜单     */    public void setActionList(List<String> actionList) {        mMenuItemNameList = actionList;    }    public void setActionSelectListener(WebChooseActionListener webChooseActionListener) {        this.mWebChooseActionListener = webChooseActionListener;    }    /**     * 暗藏隐没Action     */    public void dismissAction() {        releaseAction();    }    /**     * js选中的回掉接口     */    private class CustomJsInterface {        CustomClickWebView webView;        CustomJsInterface(CustomClickWebView c) {            webView = c;        }        /**         * @param value 选中的文字         * @param title 菜单题目         */        @JavascriptInterface        public void chooseAction(final String value, final String title) {            if (mWebChooseActionListener != null) {                mWebChooseActionListener.onChosen(title, value);            }        }    }}

应用

layout 中应用这个 CustomClickWebView

<com.rustfisher.tutorial2020.web.longmenu.CustomClickWebView    android:id="@+id/web1"    android:layout_width="match_parent"    android:layout_height="wrap_content" />

Activity 中进行初始化配置

mWv1.getSettings().setJavaScriptEnabled(true);   // 容许应用jsmWv1.setActionList(Arrays.asList("复制", "翻译"));// 自定义菜单选项mWv1.getSettings().setBlockNetworkImage(false);mWv1.linkJSInterface(); // 把js接口增加进去// 设置监听器,获取点击到的菜单和选中的文字mWv1.setActionSelectListener(new WebChooseActionListener() {    @Override    public void onChosen(String title, String selectText) {        Toast.makeText(getApplicationContext(), "(" + title + ") -> " + selectText, Toast.LENGTH_SHORT).show();    }});

(重写 startActionMode 的做法在 x5 WebView 上并不起作用。)

【Android 零根底入门教程视频参考】