自定义长按文字弹出的菜单¶
长按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
传入的名字必须一致。
"RFJSInterface.chooseAction(txt,title);"
就是在调用Java中定义的方法。
控制菜单¶
想要控制WebView中弹出的菜单,需要复写startActionMode
方法,把默认的菜单替换成自定义的菜单。调用Menu.add()
方法添加选项。
自定义的菜单选项,从外面传进来。
@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;
}
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); // 允许使用js
mWv1.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上并不起作用。
本站说明
一起在知识的海洋里呛水吧。广告内容与本站无关。如果喜欢本站内容,欢迎投喂作者,谢谢支持服务器。如有疑问和建议,欢迎在下方评论~