package com.mapbox.mapboxsdk.views; import android.os.Handler; import android.view.ScaleGestureDetector; /** * https://developer.android.com/training/gestures/scale.html * A custom gesture detector that processes gesture events and dispatches them * to the map's overlay system. */ public class MapViewScaleGestureDetectorListener implements ScaleGestureDetector.OnScaleGestureListener { private static String TAG = "MapViewScaleListener"; /** * This is the active focal point in terms of the viewport. Could be a local * variable but kept here to minimize per-frame allocations. */ private float lastFocusX; private float lastFocusY; private float firstSpan; private final MapView mapView; private boolean scaling; private float currentScale; /** * Bind a new gesture detector to a map * * @param mv a map view */ public MapViewScaleGestureDetectorListener(final MapView mv) { this.mapView = mv; } @Override public boolean onScaleBegin(ScaleGestureDetector detector) { lastFocusX = detector.getFocusX(); lastFocusY = detector.getFocusY(); firstSpan = detector.getCurrentSpan(); currentScale = 1.0f; if (!this.mapView.isAnimating()) { this.mapView.setIsAnimating(true); this.mapView.getController().aboutToStartAnimation(lastFocusX, lastFocusY); scaling = true; } return true; } @Override public boolean onScale(ScaleGestureDetector detector) { if (!scaling) { return true; } currentScale = detector.getCurrentSpan() / firstSpan; float focusX = detector.getFocusX(); float focusY = detector.getFocusY(); this.mapView.setScale(currentScale); this.mapView.getController().offsetDeltaScroll(lastFocusX - focusX, lastFocusY - focusY); this.mapView.getController().panBy(lastFocusX - focusX, lastFocusY - focusY, true); lastFocusX = focusX; lastFocusY = focusY; return true; } @Override public void onScaleEnd(ScaleGestureDetector detector) { if (!scaling) { return; } //delaying the "end" will prevent some crazy scroll events when finishing //scaling by getting 2 fingers very close to each other final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { float preZoom = mapView.getZoomLevel(false); float newZoom = (float) (Math.log(currentScale) / Math.log(2d) + preZoom); //set animated zoom so that animationEnd will correctly set it in the mapView mapView.setAnimatedZoom(newZoom); mapView.getController().onAnimationEnd(); scaling = false; } }, 100); } }