之前我们介绍了如何获取 WebView
选中的文本,今天讲讲如何获取选区的位置。
与获取选中文本类似,WebView
也没有提供相应的方法,所以同样需要通过 JS 辅助。
为了方便,可以直接在『Android 获取 WebView 选中文本』一文中的例子上直接改造。
首先是 JS 函数:
object JsFunction {
private val GET_SELECTION = """
javascript:(function getSelectedText() {
var txt;
var top = 0, bottom = 0, left = 0, right = 0;
if (window.getSelection) {
var sel = window.getSelection();
txt = sel.toString();
var range = sel.getRangeAt(0);
var rect = range.getBoundingClientRect();
top = rect.top;
bottom = rect.bottom;
left = rect.left;
right = rect.right;
} else if (window.document.getSelection) {
var sel = window.document.getSelection();
txt = sel.toString();
var range = sel.getRangeAt(0);
var rect = range.getBoundingClientRect();
top = rect.top;
bottom = rect.bottom;
left = rect.left;
right = rect.right;
} else if (window.document.selection) {
var range = window.document.selection.createRange();
txt = range.text;
var rect = range.getBoundingClientRect();
top = rect.top;
bottom = rect.bottom;
left = rect.left;
right = rect.right;
}
var json = {};
json.selection = txt;
json.left = left;
json.top = top;
json.right = right;
json.bottom = bottom;
json.windowWidth = window.innerWidth;
json.windowHeight = window.innerHeight
return json;
})()
""".trimIndent()
}
在之前的函数上,我们增加了选区上下左右四个方向的边距,用于计算选区的位置,大概思路就是获取到选区的 Rect
,然后再获取其坐标,思路与 Android 是类似的。
需要注意的是,JS 只能获取到其相对于网页窗口的坐标,与 Android 端的坐标并不是一个概念,所以同样还要返回窗口的大小用于换算。
返回的内容比较多,我们将其封装成 JSON 返回。
然后定义一个数据类用于解析返回的数据:
object JsFunction {
...
data class WebViewSelection(
val selection: String,
val left: Double,
val top: Double,
val right: Double,
val bottom: Double,
val windowWidth: Double,
val windowHeight: Double
)
}
解析数据可以用 Gson 或其他工具封装一下:
object JsFunction {
...
fun getSelection(webView: WebView, callback: (WebViewSelection?) -> Unit) {
webView.evaluateJavascript(GET_SELECTION) {
callback.invoke(Gson().fromJson(it, WebViewSelection::class.java))
}
}
}
WebView
这边执行:
class MyWebView(context: Context, attrs: AttributeSet? = null) : WebView(context, attrs) {
...
private fun getWebSelection() {
JsFunction.getSelection(this) {
if (it == null) return@getSelection
val left = (it.left / it.windowWidth * width).toInt()
val right = (it.right / it.windowWidth * width).toInt()
val top = (it.top / it.windowHeight * height).toInt()
val bottom = (it.bottom / it.windowHeight * height).toInt()
...
}
}
}
因为坐标不一致,所以要重新计算坐标,简单的比例乘除问题,不用过多解释。
接下来就可以按照自己的需求做相应的逻辑了。