自定义长按文字弹出的菜单
长按 WebView 中的文字,会有抉择光标,并且弹出一个小菜单。 个别菜单里会有「复制」,「搜寻」等等选项。
这个菜单能够由开发者自定义。让弹出的菜单显示其余选项。 比方弹出「复制」「翻译」。
个别步骤:
- 设计监听器
- 自定义WebView,复写办法
- 定义Js接口
须要新建2个 Java 文件,WebChooseActionListener,CustomClickWebView
定义监听器
监听器 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 零根底入门教程视频参考】