Lampione
Lampione

Reputation: 1608

Intercept two fingers touch on MapView inside ViewPager

So I'm trying to catch a two fingers gesture which the user should perform in order to PAN a MapView around.

The given MapView is located inside a Fragment, and the fragment is a ViewPager's page.

The expected behavior is the ViewPager default, so swiping with one finger should change page, no matter which page the user is facing.

The only exception is that if the fragment containing the MapView is showing, the user should be able to pan the map with two fingers (and with two fingers only).

What I've tried so far:

Simple XML:

<package.MapRelativeLayout>
    <com.google.android.gms.maps.MapView/>
</package.MapRelativeLayout>

and MapView wrapper:

public class MapRelativeLayout extends RelativeLayout {

    GestureDetector mGestureDetector;

    public MapRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new GestureListener());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // return super.onInterceptTouchEvent(ev);
        boolean shouldMapPan = mGestureDetector.onTouchEvent(ev);
        Log.d("MAP", "should pan: " + shouldMapPan);
        return shouldMapPan;
    }

    private class GestureListener extends GestureDetector.SimpleOnGestureListener {
        @Override
        public boolean onDown(MotionEvent e) {
            return super.onDown(e);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            // return super.onScroll(e1, e2, distanceX, distanceY);
            if (e2.getPointerCount() == 2) {
                return false;
            } else {
                return true;
            }
        }
    }

}

I wrap the MapView inside a custom ViewGroup and override the onInterceptTouchEvent, passing the MotionEvent to a custom GestureListener which listen in the onScroll for how many pointer are detected, and returns true/false otherwise, but it isn't working.

Is there any way to do this?

Upvotes: 1

Views: 518

Answers (1)

HDN
HDN

Reputation: 91

I had the same problem and I was able to solve it by doing the following...

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.UiSettings;

public class EnhanceMapView extends MapView implements OnMapReadyCallback{

    private boolean isScrollable;
    private OnMapReadyCallback onMapReadyCallback;
    private UiSettings uiSettings;

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

    public EnhanceMapView(Context context, AttributeSet attributeSet) {
        super(context, attributeSet);
    }

    public EnhanceMapView(Context context, AttributeSet attributeSet, int i) {
        super(context, attributeSet, i);
    }

    public EnhanceMapView(Context context, GoogleMapOptions googleMapOptions) {
        super(context, googleMapOptions);
    }

    @Override
    public void getMapAsync(OnMapReadyCallback onMapReadyCallback) {
        this.onMapReadyCallback = onMapReadyCallback;
        super.getMapAsync(EnhanceMapView.this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        uiSettings = googleMap.getUiSettings();
        isScrollable = false;
        uiSettings.setScrollGesturesEnabled(false);
        onMapReadyCallback.onMapReady(googleMap);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(isScrollable == uiSettings.isScrollGesturesEnabled()){
            switch (ev.getAction() & MotionEvent.ACTION_MASK) {
                case MotionEvent.ACTION_POINTER_DOWN:
                    isScrollable = true;
                    uiSettings.setScrollGesturesEnabled(true);
                    break;
                case MotionEvent.ACTION_POINTER_UP:
                    isScrollable = false;
                    uiSettings.setScrollGesturesEnabled(false);
                    break;
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return !uiSettings.isScrollGesturesEnabled() && super.onInterceptTouchEvent(ev);
    }
}

After you've create the class, you'll be able to select on the layout editor in palette/project

Upvotes: 2

Related Questions