Webview+Viewpager左右滑动冲突

问题描述

在开发场景中,经常需要Viewpager+Fragment嵌套滑动页面。然而若某个Fragment为webview,且webview中存在轮播图或者其他滑动控件,则会出现Webview内容无法左右滑动的问题。

原因分析

其实滑动冲突问题的本质,是滑动事件的分发和消费不对。

一般,我们需要明确,这个事件应该由谁来消费,实际上是谁消费了,分发过程是否正确,是否需要拦截等,想清楚这些问题基本就找到解决思路了。

若对Android事件机制不够熟悉,可以先温习一遍事件机制原理再往下看。

在上述的问题场景中,我们可以确定正确思路:这个事件应该由webivew先响应,如果webview不需要内部滑动了(左右滑到边了),再交给Viewpage处理事件。

解决方案

1.WebView onTouchEvent方法

查找父组件是否为可以滑动的视图(如ViewPager),是则调用requestDisallowInterceptTouchEvent(true),请求父组件不要拦截

2.WebView onOverScrolled

当clampedX或者clampedY值为true,此时不再响应内部滑动。调用requestDisallowInterceptTouchEvent(false),请求父组件恢复拦截

核心代码

//最大递归深度,避免异常,防止嵌套层级导致判断无效
int MAX_PARENT_DEPTH = 3;

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        ViewParent viewParent = findViewParentIfNeeds(this, MAX_PARENT_DEPTH);
        if(viewParent != null){
            // 父组件不要拦截
            viewParent.requestDisallowInterceptTouchEvent(true);
        }
    }
    return super.onTouchEvent(event);
}

private ViewParent findViewParentIfNeeds(View tag, int depth){

    if (depth < 0) {
        return null;
    }

    ViewParent parent = tag.getParent();
    if (parent == null) {
        return null;
    }

    if (parent instanceof ScrollView || parent instanceof ViewPager){
        return parent;
    }
    return findViewParentIfNeeds((View) parent, depth - 1);
}
@Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY){
    if (clampedX || clampedY) {
        ViewParent viewParent = findViewParentIfNeeds(this, MAX_PARENT_DEPTH);
        if (viewParent != null) {
            // 父组件可以根据自身判断来决定是否拦截
            viewParent.requestDisallowInterceptTouchEvent(false);
        }
    }

    super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
}

参考文档

处理 WebView 与 ViewPager 滑动冲突 - 技术小黑屋

你可能感兴趣的:(H5,Android,webview,javascript,android)