1

I am trying to detect the onDoubleTap zoom on googleMap in anroid (only zoom neither scroll nor rotate/tilt).Actually I want to achieve that zooming concept which is used by uber like if you double tap on map the marker is as stable as it was on the location before zoom on the map, I mean the coordinates should be the same no matter what is the zooming level.For example if I double tap anywhere on map it should always zoom in to the center of the mapView.

Nirmal Prajapat
  • 1,735
  • 1
  • 12
  • 23
  • Possible duplicate of [Double Tap -> Zoom on Android MapView?](https://stackoverflow.com/questions/2691235/double-tap-zoom-on-android-mapview) – Gowthaman M Feb 19 '18 at 05:51

1 Answers1

1

You can modify public boolean dispatchTouchEvent(MotionEvent event) in that answer for your previous question for detect double taps on delays between first and second taps, for example that way:

public class TouchableWrapper extends FrameLayout {

    private GoogleMap mGoogleMap = null;
    private long mLastTouchTime = -1;      // time of first tap

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

    public void setGoogleMap(GoogleMap googleMap) {
        mGoogleMap = googleMap;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);

                long thisTime = System.currentTimeMillis();  // time of second tap tap
                if (thisTime - mLastTouchTime < ViewConfiguration.getDoubleTapTimeout()) {
                    // double tap detected! do you magic here:
                    if (mGoogleMap != null) {
                        LatLng zoomCenter = mGoogleMap.getProjection().fromScreenLocation(new Point((int)event.getX(), (int)event.getY()));
                                                    mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(zoomCenter, currentZoom + 1));
                    }
                    mLastTouchTime = -1;
                } else {
                    mLastTouchTime = thisTime;
                    mGoogleMap.getUiSettings().setZoomGesturesEnabled(true);
                }

            break;

            case MotionEvent.ACTION_POINTER_DOWN:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(false);
            break;

            case MotionEvent.ACTION_POINTER_UP:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);
            break;

            case MotionEvent.ACTION_UP:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);
            break;
        }

        return super.dispatchTouchEvent(event);
    }
}

UPDATE:

If you use MapView instead of MapFregment - better way is to create custom view, which extends MapView implements OnMapReadyCallback (it's neccessary for get GoogleMap object), and overrides dispatchTouchEvent() (for double tap detection). Something like that:

public class EnhanchedMapView extends MapView implements OnMapReadyCallback {
    private long mLastTouchTime = -1;

    private OnMapReadyCallback mMapReadyCallback;
    private GoogleMap mGoogleMap;
    private Marker mMarker;
    private Paint mPaintArrow;

    public EnhanchedMapView(@NonNull Context context) {
        super(context);
        init();
    }

    public EnhanchedMapView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public EnhanchedMapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public EnhanchedMapView(@NonNull Context context, @Nullable GoogleMapOptions options) {
        super(context, options);
        init();
    }

    private void init() {
    }

    @Override
    public void getMapAsync(OnMapReadyCallback callback) {
        mMapReadyCallback = callback;
        super.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);

                long thisTime = System.currentTimeMillis();
                if (thisTime - mLastTouchTime < ViewConfiguration.getDoubleTapTimeout()) {

                    if (mGoogleMap != null) {
                        LatLng zoomCenter = mGoogleMap.getProjection().fromScreenLocation(new Point((int) event.getX(), (int) event.getY()));
                        float currentZoom = mGoogleMap.getCameraPosition().zoom;
                        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(zoomCenter, currentZoom + 1));
                    }
                    mLastTouchTime = -1;
                } else {
                    mLastTouchTime = thisTime;
                    mGoogleMap.getUiSettings().setZoomGesturesEnabled(true);
                }

                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(false);
                break;

            case MotionEvent.ACTION_POINTER_UP:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);
                break;

            case MotionEvent.ACTION_UP:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);
                break;
        }

        return super.dispatchTouchEvent(event);
    }
}

UPDATE #2:

Activity layout for activity (MainActivity) that case can be like:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="{YOUR_PACKAGE}.MainActivity">

    <{YOUR_PACKAGE}.EnhanchedMapView
        android:id="@+id/mapview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        />

</RelativeLayout>

And only changes in MainActivity source code is:

...
private EnhanchedMapView mMapView;
...

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ...
    mMapView = (EnhanchedMapView) findViewById(R.id.mapview);
    ...
}

UPDATE #3:

public class EnhanchedMapView extends MapView implements OnMapReadyCallback {
    private long mLastTouchTime = -1;

    private OnMapReadyCallback mMapReadyCallback;
    private GoogleMap mGoogleMap;

    private LatLng mZoomCenter;

    public EnhanchedMapView(@NonNull Context context) {
        super(context);
        init();
    }

    public EnhanchedMapView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public EnhanchedMapView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public EnhanchedMapView(@NonNull Context context, @Nullable GoogleMapOptions options) {
        super(context, options);
        init();
    }

    private void init() {
    }

    @Override
    public void getMapAsync(OnMapReadyCallback callback) {
        mMapReadyCallback = callback;
        super.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mGoogleMap = googleMap;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);
                mGoogleMap.getUiSettings().setZoomGesturesEnabled(false);

                mZoomCenter = mGoogleMap.getCameraPosition().target;

                long thisTime = System.currentTimeMillis();
                if (thisTime - mLastTouchTime < ViewConfiguration.getDoubleTapTimeout()) {

                    if (mGoogleMap != null) {
                        LatLng zoomCenter = mGoogleMap.getProjection().fromScreenLocation(new Point((int) event.getX(), (int) event.getY()));
                        float currentZoom = mGoogleMap.getCameraPosition().zoom;
                        mGoogleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mZoomCenter, currentZoom + 1));
                    }
                    mLastTouchTime = -1;
                } else {
                    mLastTouchTime = thisTime;
                    mGoogleMap.getUiSettings().setZoomGesturesEnabled(true);
                }

                break;

            case MotionEvent.ACTION_POINTER_DOWN:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(false);
                break;

            case MotionEvent.ACTION_POINTER_UP:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);
                break;

            case MotionEvent.ACTION_UP:
                mGoogleMap.getUiSettings().setScrollGesturesEnabled(true);
                break;
        }

        return super.dispatchTouchEvent(event);
    }
}
Andrii Omelchenko
  • 13,183
  • 12
  • 43
  • 79
  • Of course. In much easy way - just override `dispatchTouchEvent()`. Please see updated answer. – Andrii Omelchenko Feb 19 '18 at 12:40
  • There is no need to use `TouchableWrapper ` in this case (it's only for `MapFragment` approach of Google Map API using). Do everything inside your custom MapView (`EnhanchedMapView` in example above). Just use `EnhanchedMapView` instead `MapView` in your app. – Andrii Omelchenko Feb 19 '18 at 12:52
  • Its working but I want to always zoom in to the center of the map view no matter where is doubleTap event is performed on mapView. – Nirmal Prajapat Feb 20 '18 at 05:09
  • @NirmalPrajapat Please see UPDATE #3 (you should get current map center before zoom and use it,). – Andrii Omelchenko Feb 20 '18 at 09:39
  • thnks@AndriiOmelchenko, one more thing i would like to ask is how to detect if pinch zoom in performed or pinch zoom out performed on mapView – Nirmal Prajapat Feb 20 '18 at 10:10
  • @NirmalPrajapat Yes it's separate question (but it can be solved by the same way - overriding `dispatchTouchEvent()` method) – Andrii Omelchenko Feb 20 '18 at 15:20
  • have a look at this https://stackoverflow.com/questions/48899656/how-to-get-if-pinch-zoom-in-is-performed-or-pinch-zoom-out-in-android – Nirmal Prajapat Feb 21 '18 at 06:46