【问题标题】:Android ScrollView stealing touch events from child WebViewAndroid ScrollView 从子 WebView 窃取触摸事件
【发布时间】:2019-01-17 12:47:10
【问题描述】:

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

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

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

【问题讨论】:

    标签: java android android-webview android-scrollview


    【解决方案1】:

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

    Reference Link

    还有一些代码

    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);
    

    希望这能达到目的。

    【讨论】:

      【解决方案2】:

      我通过在与 ScrollView 相同的层次结构级别的屏幕上添加一个浮动 WebView 来解决此问题,并将其位置链接到滚动值,然后使用 WebView.BringToFront 和 ScrollView.BringToFront 切换触摸控制

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-29
        • 1970-01-01
        • 2012-02-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多