在这次改版中,h5小伙伴与我沟通说要把长按选择改用成原生的拉选框,之前我也没搞过呀,开始研究吧。
怎么研究呀,当然是百度一下了。
百度了一天总结如下:
好多文章都是告诉你如何在系统的基础上来修改自己的文字和点击事件。
要么就是与H5配合让H5小伙伴控制 拉选框,你来弹框(我们之前就是这样的)。
现在我要实现的是长按webview后弹出来的拉选框(就是两个可以滑动的图标、用来选择文字的)要用android系统自带的,然后弹出的菜单栏要我们android自己自定义的弹框(以前就是自定义,许多功能都是写好的,我们还有单击也会弹这个框)。
说那么多鬼知道你要实现什么啊,直接上截图!
就是这样的效果。
怎么实现呢,其实很简单呀,首先我们自定义webview,然后重写startActionMode方法
是的跟他们之前一样。上代码
@Override
public ActionMode startActionMode(ActionMode.Callback callback) {
ActionMode actionMode = super.startActionMode(buildCustomCallback(callback));
actionMode.getMenu().clear();
return actionMode;
}
@Override
public ActionMode startActionMode(ActionMode.Callback callback, int type) {
ActionMode actionMode = super.startActionMode(buildCustomCallback(callback), type);
actionMode.getMenu().clear();
return actionMode;
}
buildCustomCallback() 这个方法是干什么的呀,其实也没啥就是自定义了个 ActionMode.Callback
代码如下
private ActionMode.Callback buildCustomCallback(final ActionMode.Callback callback) {
return new ActionMode.Callback2() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
LogUtil.d(TAG, "buildCustomCallback onCreateActionMode");
if (mode.getMenu() != null)
mode.getMenu().clear();
return callback.onCreateActionMode(mode, menu);
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
LogUtil.d(TAG, "buildCustomCallback onPrepareActionMode");
callback.onPrepareActionMode(mode, menu);
if (isFirst && textSelectedListener != null) {
textSelectedListener.OnTextSelected(markTop, markLeft);
markTop = 0;
markLeft = 0;
}
if (mode.getMenu() != null)
mode.getMenu().clear();
return true;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
LogUtil.d(TAG, "buildCustomCallback onActionItemClicked");
if (item == null || TextUtils.isEmpty(item.getTitle())) {
return callback.onActionItemClicked(mode, item);
}
String title = item.getTitle().toString();
return callback.onActionItemClicked(mode, item);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
LogUtil.d(TAG, "buildCustomCallback onDestroyActionMode");
if (mode != null)
mode.invalidate();
callback.onDestroyActionMode(mode);
}
@Override
public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
int height = outRect.height();
float exactY = outRect.exactCenterY();
LogUtil.d(TAG, exactY + " --- " + height + " buildCustomCallback onGetContentRect:" + outRect.top + " centerX:" + outRect.centerX());
if (outRect.top != 0) {
isFirst = true;
markTop = outRect.top;
// markLeft = outRect.left > 0 ? outRect.left : 0;
markLeft = outRect.centerX();
} else {
isFirst = false;
}
if (callback instanceof ActionMode.Callback2) {
ActionMode.Callback2 tempCallback2 = (ActionMode.Callback2) callback;
tempCallback2.onGetContentRect(mode, view, outRect);
} else {
super.onGetContentRect(mode, view, outRect);
}
}
};
}
这里面有一个
@Override
public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
}
这里面的 outRect 非常重要因为我就是从这个地方获取的拉选框位置的,怎么获取呢很简单直接拿它的top和left就可以了呀。
研究了一天半终于实现这个功能了,确实不容易呀,然后就开始测试发现竟然有bug,就是位置竟然不对劲,比如我从第三行开始选择,我拉都第二行拉到第一行,看着对劲,然后再从第一行拉到第二行的时候竟然位置不对了,怎么回事!位置竟然跑到选择第一行的位置了,明明在第二行啊,又是一堆研究测试终于发现问题了,原来是因为他这个方法永远返回差了一行的位置!
找到问题该怎么解决啊,难道是系统bug???这咋弄
想尽脑汁也不知道该怎么处理,在网上各种搜索,偏偏关于webview长按文字选择这样的文章少的可怜,有也是几乎抄袭的就那么几篇。怎么办
于是我想着既然他一直少一行那么我手动让它给咱们刷新不就行了,我找一下看看有没有刷新方法,
mode.invalidate();
没错就是这个方法,我们手动让ActionMode给咱们刷新不就好了,于是我就测试先放在了 onGetContentRect ,一运行直接卡死了,哈哈,于是又想放到onDestroyActionMode比较好,测试跑起来没问题!搞定了,可以愉快的玩耍了!
demo没写 代码直接从项目中拿出来的,要是有小伙伴看不懂,留言我去写个demo放到git上。