首页 > 解决方案 > Android ScrollView 从子 WebView 窃取触摸事件

问题描述

我有一个布局,其中 aWebView在 ScrollView 内,我希望能够在这两者之间切换以决定哪一个接收触摸事件。不幸的是,无论我做什么,ScrollView 似乎都从 WebView 窃取了触摸事件,从而无法在 WebView 中平滑地平移和缩放。有什么解决办法吗?

我尝试ScrollView.SetOnTouchListener();并设置了一个返回 true 的侦听器,这会阻止 ScrollView 滚动,但不会阻止触摸事件在到达 WebView 之前被拦截。

我也试过了WebView.Parent.RequestDisallowInterceptTouchEvent(true);WebView.Parent.RequestDisallowInterceptTouchEvent(true);似乎都没有效果。

标签: javaandroidandroid-webviewandroid-scrollview

解决方案


尝试使用NestedScrollView并实现NestedScrollingChild自定义 WebView。

参考链接

和一些代码

public class NestedWebView extends WebView implements NestedScrollingChild {
private int mLastY;
private final int[] mScrollOffset = new int[2];
private final int[] mScrollConsumed = new int[2];
private int mNestedOffsetY;
private NestedScrollingChildHelper mChildHelper;

public NestedWebView(Context context) {
    this(context, null);
}

public NestedWebView(Context context, AttributeSet attrs) {
    this(context, attrs, android.R.attr.webViewStyle);
}

public NestedWebView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mChildHelper = new NestedScrollingChildHelper(this);
    setNestedScrollingEnabled(true);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
    boolean returnValue = false;

    MotionEvent event = MotionEvent.obtain(ev);
    final int action = MotionEventCompat.getActionMasked(event);
    if (action == MotionEvent.ACTION_DOWN) {
        mNestedOffsetY = 0;
    }
    int eventY = (int) event.getY();
    event.offsetLocation(0, mNestedOffsetY);
    switch (action) {
        case MotionEvent.ACTION_MOVE:
            int deltaY = mLastY - eventY;
            // NestedPreScroll
            if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
                deltaY -= mScrollConsumed[1];
                mLastY = eventY - mScrollOffset[1];
                event.offsetLocation(0, -mScrollOffset[1]);
                mNestedOffsetY += mScrollOffset[1];
            }
            returnValue = super.onTouchEvent(event);

            // NestedScroll
            if (dispatchNestedScroll(0, mScrollOffset[1], 0, deltaY, mScrollOffset)) {
                event.offsetLocation(0, mScrollOffset[1]);
                mNestedOffsetY += mScrollOffset[1];
                mLastY -= mScrollOffset[1];
            }
            break;
        case MotionEvent.ACTION_DOWN:
            returnValue = super.onTouchEvent(event);
            mLastY = eventY;
            // start NestedScroll
            startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL);
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            returnValue = super.onTouchEvent(event);
            // end NestedScroll
            stopNestedScroll();
            break;
    }
    return returnValue;
}

// Nested Scroll implements
@Override
public void setNestedScrollingEnabled(boolean enabled) {
    mChildHelper.setNestedScrollingEnabled(enabled);
}

@Override
public boolean isNestedScrollingEnabled() {
    return mChildHelper.isNestedScrollingEnabled();
}

@Override
public boolean startNestedScroll(int axes) {
    return mChildHelper.startNestedScroll(axes);
}

@Override
public void stopNestedScroll() {
    mChildHelper.stopNestedScroll();
}

@Override
public boolean hasNestedScrollingParent() {
    return mChildHelper.hasNestedScrollingParent();
}

@Override
public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed,
                                    int[] offsetInWindow) {
    return mChildHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow);
}

@Override
public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) {
    return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
}

@Override
public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
    return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed);
}

@Override
public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
    return mChildHelper.dispatchNestedPreFling(velocityX, velocityY);
}

}

声明 NestedWebView 而不是在 NestedScrollView 中声明 WebView。例如

<com.nestedscrollwebviewexample.NestedWebView
    android:id="@+id/nested_webview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#000000"
    android:fillViewport="true"
    android:focusable="true"
    android:isScrollContainer="false"
    android:visibility="visible"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    app:layout_scrollFlags="scroll|exitUntilCollapsed" />

您可以在 Activity 中初始化为 NestedWebView 而不是声明 Webview

 private NestedWebView mShopWebView;
    mShopWebView = (NestedWebView) findViewById(R.id.url_load_webview);

希望这能达到目的。


推荐阅读