Intercept Android Google Maps Touch and Click

August 15, 2017

I want to intercept all click and touch on Google Maps fragment.

For my use case, I have a small map fragment in my activity. Once user click or touch or drag or pinch on the map fragment, it will launch an activity with a fullscreen map.

GoogleMap listeners

The easiest method is to utilize GoogleMap’s listeners:

  • setOnMapClickListener - the map is clicked (will not trigger if marker is clicked)
  • setOnMarkerClickListener - the marker is clicked
  • setOnCameraMoveStartedListener - touch, drag or pinch event (scroll and zoom)
mapFragment.getMapAsync(new OnMapReadyCallback() {
    @Override
    public void onMapReady(final GoogleMap map) {

        map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng latLng) {
                Log.d(TAG, "onMapClick");
                startMap();
            }
        });

        map.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
            @Override
            public void onCameraMoveStarted(int reason) {
                if (reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE) {
                    Log.d(TAG, "onCameraMoveStarted");
                    startMap();
                }
            }
        });

        map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
            @Override
            public boolean onMarkerClick(Marker marker) {
                Log.d(TAG, "onMarkerClick");
                startMap();
                return true;
            }
        });
    }
});    

I want the map to remain static, where it cannot be scrolled or zoomed by the user. The above listeners doesn’t prevent that.

I can use map.getUiSettings().setAllGesturesEnabled(false) to disable gestures and make the map static. The problem is that only the click listener are triggered, where nothing happens if user touch, drag or pinch the map. I want to receive an event when user touch, drag or pinch the map.

// disable all gestures, OnCameraMoveStartedListener will not be triggered
map.getUiSettings().setAllGesturesEnabled(false);

Extend SupportMapFragment with TouchableWrapper

To intercept all click and touch events and prevent the events from being replayed to Google Maps, we need extend SupportMapFragment.

We add a FrameLayout as an overlay on map view, overriding dispatchTouchEvent and consume all MotionEvent.ACTION_DOWN events.

public class StaticMapFragment extends SupportMapFragment {
    public View mapView;
    public TouchableWrapper touchView;
    private StaticMapFragment.OnTouchListener listener;

    public static StaticMapFragment newInstance() {
        return new StaticMapFragment();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        mapView = super.onCreateView(inflater, parent, savedInstanceState);
        // overlay a touch view on map view to intercept the event
        touchView = new TouchableWrapper(getActivity());
        touchView.addView(mapView);
        return touchView;
    }

    @Override
    public View getView() {
        return mapView;
    }

    public void setOnTouchListener(StaticMapFragment.OnTouchListener listener) {
        this.listener = listener;
    }

    public interface OnTouchListener {
        void onTouch();
    }

    public class TouchableWrapper extends FrameLayout {
        public TouchableWrapper(Context context) {
            super(context);
        }

        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    if (listener != null) {
                        listener.onTouch();
                    }
                    // consume event to prevent map from receiving the event
                    return true;
            }
            return super.dispatchTouchEvent(event);
        }
    }
}

Usage.

mapFragment.setOnTouchListener(new StaticMapFragment.OnTouchListener() {
    @Override
    public void onTouch() {
        Log.d(TAG, "onTouch");
        startMap();
    }
});

References

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.