requestDisallowInterceptTouchEvent for Scrollview

2019-09-13 18:51发布

问题:

I have a StreetViewPanoramaView inside a linearlayout inside a scrollview:

  <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/scrollview">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:id="@+id/linear">

            <com.google.android.gms.maps.StreetViewPanoramaView
                android:id="@+id/street_view_panorama"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

                <other views - textviews etc>

        </LinearLayout>

    </ScrollView>

The StreetViewPanoramaView allows a user to move the streetview camera up and down and left and right. I want the scrollview to stop intercepting the user touch events when the user is moving the camera. Currently, if the user moves the camera in the StreetViewPanoramaView, the scrollview intercept the touch and moves the scrollview instead.

I tried this code from https://mobiarch.wordpress.com/2013/11/21/prevent-touch-event-theft-in-android/ but its doesn't seem to be working (scrollview is still taking the touch events):

      mStreetViewPanoramaView = (StreetViewPanoramaView) findViewById(R.id.street_view_panorama);
        LinearLayout.LayoutParams streetViewLp =
                new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, displaymetrics.widthPixels/3);
        mStreetViewPanoramaView.setLayoutParams(streetViewLp);

        disableTouchTheft(mStreetViewPanoramaView);

public static void disableTouchTheft(View view) {
    view.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            view.getParent().getParent().requestDisallowInterceptTouchEvent(true);
            switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_UP:
                view.getParent().getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }
            return false;
        }
    });
}

EDIT:

Things I have tried:

I have made a custom view and imported the code dispatchTouchEvent into my activity code:

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        int[] loc = {0, 0};
        mStreetViewPanoramaView.getLocationOnScreen(loc);

        Rect rect = new Rect(loc[0], loc[1] , loc[0] + mStreetViewPanoramaView.getWidth(), loc[1] + mStreetViewPanoramaView.getHeight());


        if (rect.contains((int) event.getRawX(), (int) event.getRawY())) {
            Log.e("stretview", "dispatched");
            return mStreetViewPanoramaView.dispatchTouchEvent(event);
/*            return true;*/

        }else{
            //Continue with touch event
            return super.dispatchTouchEvent(event);
        }
    }

public class CustomStreetViewPanoramaView extends StreetViewPanoramaView {

    public CustomStreetViewPanoramaView(Context context) {
        super(context);
    }

    public CustomStreetViewPanoramaView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomStreetViewPanoramaView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public CustomStreetViewPanoramaView(Context context, StreetViewPanoramaOptions options) {
        super(context, options);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return false; // Do not intercept touch event, let the child handle it
    }
}

The code appears to half-work - it appears that the StreetViewParnoramaView will obtain the touch events for the top half of the view but the bottom half does not obtain any touch events.

My full layout file:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:id="@+id/container"
    android:layout_height="match_parent">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/scrollview">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:id="@+id/linearlayout">

            <com.example.simon.customshapes.CustomStreetViewPanoramaView
                android:id="@+id/street_view_panorama"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

            <android.support.v7.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="500dp"
                android:id="@+id/card"
                >
                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Hello card"
                    android:layout_gravity="center" />

            </android.support.v7.widget.CardView>

            <TextView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Save panorama"
                android:padding="8dp"
                android:id="@+id/savepano"/>

            <android.support.v7.widget.RecyclerView
                android:id="@+id/my_recycler_view"
                android:scrollbars="vertical"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
            </android.support.v7.widget.RecyclerView>

        </LinearLayout>
    </ScrollView>

</LinearLayout> 

回答1:

The answer of Johann is the right path but still not working - this one will work

    @Override
public boolean dispatchTouchEvent(MotionEvent event) {

    if (streetView != null) {
        streetView.getGlobalVisibleRect(rect);

        if (rect.contains((int) event.getRawX(), (int) event.getRawY())) {
            event.offsetLocation(-rect.left, -rect.top);
            streetView.dispatchTouchEvent(event);
            return true;

        } else {
            //Continue with touch event
            return super.dispatchTouchEvent(event);
        }
    } else {
        return super.dispatchTouchEvent(event);
    }
}

dispatchTouchEvent of the activity and move the event after offsets it to the streetView



回答2:

Can you try the following...

@Override
public boolean dispatchTouchEvent(MotionEvent event) {

    int[] loc = {0, 0};
    mStreetViewPanoramaView.getLocationOnScreen(loc);

    Rect rect = new Rect(loc[0], loc[1] , loc[0] + mStreetViewPanoramaView.getWidth(), loc[1] + mStreetViewPanoramaView.getHeight());


    if (rect.contains((int) event.getRawX(), (int) event.getRawY())) {            
        mStreetViewPanoramaView.dispatchTouchEvent(event);
        return true;

    }else{
        //Continue with touch event
        return super.dispatchTouchEvent(event);
    }
}

This hopefully will check if the touch was on the panoramaview and handle accordingly.