我有一个SwipeRefreshLayout视图作为父级。在其中我使用加载网页的webview。我想通过拉下SwipeRefreshLayout来重新加载webview。这是我的xml:
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/refresh_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.widget.SwipeRefreshLayout>
和java代码:
mWebView = (WebView) view.findViewById(R.id.webView);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.loadUrl("http://kashirskoe.vegas-city.ru/renter/");
mSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.refresh_layout);
mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mSwipeRefreshLayout.setRefreshing(true);
mSwipeRefreshLayout.postDelayed(new Runnable() {
@Override
public void run() {
mWebView.reload();
mSwipeRefreshLayout.setRefreshing(false);
}
}, 1000);
}
});
乍一看它完美无缺。但是当用户向下滚动例如网页上的地图控件时,它不滚动。而不是这个SwipeRefreshLayout拦截滚动和刷新网页(示例页面网址在代码上)。
我希望在页面上的任何Web控件滚动时禁用SwipeRefreshLayout滚动。喜欢它在浏览器谷歌浏览器中工作。
我认为我需要在webview中注入并执行JavaScript,以便检测页面上任何滚动控件上的滚动事件。并将其传递给Android本机代码。我知道如何将它传递给本机代码。
但我怎样才能在javascript中检测到这个滚动事件?
答案 0 :(得分:5)
您可以通过定义扩展WebView并覆盖方法onOverScrolled
doc here的自定义WebView类来检测WebView的内容是否滚动。
从禁用SwipeRefreshLayout开始,并在WebView中的内容不滚动时启用它。然后,您可以通过捕获WebView上发生的触摸DOWN事件来检测滚动手势。
public class MyWebView extends WebView{
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
if( clampedX || clampedY ){
//Content is not scrolling
//Enable SwipeRefreshLayout
ViewParent parent = this.getParent();
if ( parent instanceof SwipeRefreshLayout) {
((SwipeRefreshLayout)parent).setEnabled(true);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
if(event.getActionMasked()==MotionEvent.ACTION_DOWN){
//Disable SwipeRefreshLayout
ViewParent parent = this.getParent();
if ( parent instanceof SwipeRefreshLayout) {
((SwipeRefreshLayout)parent).setEnabled(false);
}
}
return true;
}
}
答案 1 :(得分:0)
webview 的内容滚动完美。我想检测网页上任何元素的滚动,但不是所有 webview 的内容。例如在页面上除其他外布置地图元素。我可以滚动它。但是当添加SwipeRefreshLayout时,地图元素的滚动被拦截了。
根据您的评论,我想我已经处理过类似的问题。这是我在 webview 中检测元素滚动的解决方案。
该解决方案在 webview 完成加载后向 webview 添加一个 onTouchStart 侦听器,以记录网页中元素或其祖先的有效可滚动触摸,然后将触摸的必要信息发送回您的本机代码以进行进一步操作。
首先,我们需要启用webview的JavaScript,并为webview添加一个javascript接口来接收触摸信息。在 Kotlin 中应该是这样的:
webview.settings.javaScriptEnabled = true
webview.addJavascriptInterface(scrollableWebViewJSInterfaceObject, "scrollableWebViewJSInterface") // We name the interface as scrollableWebViewJSInterface
在这个scrollableWebViewJSInterfaceObject
中,我们需要实现两个函数作为javascript接口回调,如下所示:
@JavascriptInterface
@Suppress("UNUSED") // Used by javascript callback
fun touchOnScrollableWebElement(
scrollLeft: Int,
scrollTop: Int,
scrollLeftMax: Int,
scrollTopMax: Int
) {
// May check whether the element can scroll according to its scrolling direction.
// And if it can scroll, you should swallow the touch here and disallow your SwipeRefreshLayout to scroll.
// Otherwise, let SwipeRefreshLayout scroll.
}
@JavascriptInterface
@Suppress("UNUSED") // Used by javascript callback
fun touchOnNotScrollableWebElement() {
// If a touch in the web view does not on any scrollable element.
// Just let SwipeRefreshLayout do whatever it wants.
}
如果 Web 视图中的触摸位于可滚动元素上,则调用 touchOnScrollableWebElement()
以进行进一步检查。否则,调用 touchOnNotScrollableWebElement()
。
其次,我们应该在webview加载完页面后在JS中添加触摸监听器。
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
registerWebElementsTouchCallback(view)
}
private fun registerWebElementsTouchCallback(view: WebView) {
// Add a "touchstart" listener to watch all touched elements.
// If a touch down on an element, we check whether the element is scrollable or anyone of
// its ancestors is scrollable in order to let the webview's scrollable container know whether it can scroll.
// The elements rendered in the web view are not immediate descendant views of the web view
// and cannot be accessed directly in android codes. As a result, to determine whether they
// are scrollable and can be scrolling at the time, we have to add javascript interface and
// execute javascript codes here.
val javascript = "function onTouchStart(event) { \n" +
"if (event.targetTouches.length >= 1) { \n" +
"var touch = event.targetTouches[0]; \n" +
"if (touch.target) { \n" +
"var node = touch.target; \n" +
"while(node) { \n" +
"var scrollLeftMax = node.scrollWidth - node.clientWidth; \n" +
"var scrollTopMax = node.scrollHeight - node.clientHeight; \n" +
"if (scrollLeftMax > 0 || scrollTopMax > 0) { \n" +
"window.scrollableWebViewJSInterface.touchOnScrollableWebElement(node.scrollLeft, " +
"node.scrollTop, scrollLeftMax, scrollTopMax); \n" +
"break; \n" +
"} \n" +
"node = node.parentNode; \n" +
"} \n" +
"if (!node) { \n" +
"window.scrollableWebViewJSInterface.touchOnNotScrollableWebElement(); \n" +
"} \n" +
"} \n" +
"} \n" +
"} \n" +
"window.addEventListener('touchstart', onTouchStart, true);\n"
view.evaluateJavascript(javascript, null)
}
如你所见,JS代码通过scrollWidth和clientWidth检查元素是否可以滚动,然后调用相应的JS接口函数。有关这些变量的更多信息可以在文档中找到。我觉得除了字符串格式,代码很简单。
最后,如果应用正确,此解决方案应该适用于您的情况。
希望这可以帮助遇到类似问题的人。