diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 6156b3af7..42aa9206e 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -73,6 +73,11 @@ public class MapboxConstants { */ public static final long VELOCITY_THRESHOLD_IGNORE_FLING = 1000; + /** + * Vertical angle threshold for a horizontal disabled fling gesture + */ + public static final long ANGLE_THRESHOLD_IGNORE_VERTICAL_FLING = 75; + /** * Value by which the default rotation threshold will be increased when scaling * @@ -195,6 +200,7 @@ public class MapboxConstants { public static final String STATE_CAMERA_POSITION = "mapbox_cameraPosition"; public static final String STATE_ZOOM_ENABLED = "mapbox_zoomEnabled"; public static final String STATE_SCROLL_ENABLED = "mapbox_scrollEnabled"; + public static final String STATE_HORIZONAL_SCROLL_ENABLED = "mapbox_horizontalScrollEnabled"; public static final String STATE_ROTATE_ENABLED = "mapbox_rotateEnabled"; public static final String STATE_TILT_ENABLED = "mapbox_tiltEnabled"; public static final String STATE_DOUBLE_TAP_ENABLED = "mapbox_doubleTapEnabled"; diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 461db80c6..3deed84cf 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -7,8 +7,10 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.PointF; import android.os.Handler; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; + import android.view.InputDevice; import android.view.MotionEvent; import android.view.animation.DecelerateInterpolator; @@ -423,9 +425,6 @@ final class MapGestureDetector { return false; } - transform.cancelTransitions(); - cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - // tilt results in a bigger translation, limiting input for #5281 double tilt = transform.getTilt(); double tiltFactor = 1.5 + ((tilt != 0) ? (tilt / 10) : 0); @@ -434,6 +433,17 @@ final class MapGestureDetector { // calculate animation time based on displacement long animationTime = (long) (velocityXY / 7 / tiltFactor + MapboxConstants.ANIMATION_DURATION_FLING_BASE); + if (!uiSettings.isHorizontalScrollGesturesEnabled()) { + // determine if angle of fling is valid for performing a vertical fling + double angle = Math.abs(Math.toDegrees(Math.atan(offsetX / offsetY))); + if (angle > MapboxConstants.ANGLE_THRESHOLD_IGNORE_VERTICAL_FLING) { + return false; + } + offsetX = 0.0; + } + + transform.cancelTransitions(); + cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); // update transformation transform.moveBy(offsetX, offsetY, animationTime); @@ -476,6 +486,11 @@ final class MapGestureDetector { // dispatching camera start event only when the movement actually occurred cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_GESTURE); + // Disable scrolling horizontal if not allowed + if (!uiSettings.isHorizontalScrollGesturesEnabled()) { + distanceX = 0; + } + // Scroll the map transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 8867d0768..3a2040095 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -7,12 +7,14 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; + import androidx.annotation.ColorInt; import androidx.annotation.IntRange; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.core.content.res.ResourcesCompat; + import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; @@ -65,6 +67,7 @@ public class MapboxMapOptions implements Parcelable { private boolean rotateGesturesEnabled = true; private boolean scrollGesturesEnabled = true; + private boolean horizontalScrollGesturesEnabled = true; private boolean tiltGesturesEnabled = true; private boolean zoomGesturesEnabled = true; private boolean doubleTapGesturesEnabled = true; @@ -127,6 +130,7 @@ public class MapboxMapOptions implements Parcelable { rotateGesturesEnabled = in.readByte() != 0; scrollGesturesEnabled = in.readByte() != 0; + horizontalScrollGesturesEnabled = in.readByte() != 0; tiltGesturesEnabled = in.readByte() != 0; zoomGesturesEnabled = in.readByte() != 0; doubleTapGesturesEnabled = in.readByte() != 0; @@ -191,6 +195,8 @@ public class MapboxMapOptions implements Parcelable { typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiZoomGestures, true)); mapboxMapOptions.scrollGesturesEnabled( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiScrollGestures, true)); + mapboxMapOptions.horizontalScrollGesturesEnabled( + typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiHorizontalScrollGestures, true)); mapboxMapOptions.rotateGesturesEnabled( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_uiRotateGestures, true)); mapboxMapOptions.tiltGesturesEnabled( @@ -261,7 +267,7 @@ public class MapboxMapOptions implements Parcelable { mapboxMapOptions.setPrefetchesTiles( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableTilePrefetch, true)); mapboxMapOptions.setPrefetchZoomDelta( - typedArray.getInt(R.styleable.mapbox_MapView_mapbox_prefetchZoomDelta, 4)); + typedArray.getInt(R.styleable.mapbox_MapView_mapbox_prefetchZoomDelta, 4)); mapboxMapOptions.renderSurfaceOnTop( typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false)); @@ -546,6 +552,18 @@ public class MapboxMapOptions implements Parcelable { return this; } + /** + * Specifies if the horizontal scroll gesture is enabled for a map view. + * + * @param enabled True and gesture will be enabled + * @return This + */ + @NonNull + public MapboxMapOptions horizontalScrollGesturesEnabled(boolean enabled) { + horizontalScrollGesturesEnabled = enabled; + return this; + } + /** * Specifies if the tilt gesture is enabled for a map view. * @@ -652,7 +670,7 @@ public class MapboxMapOptions implements Parcelable { * tile at the (current_zoom_level - delta) is rendered as soon as possible at the * expense of a little bandwidth. * Note: This operation will override the MapboxMapOptions#setPrefetchesTiles(boolean) - * Setting zoom delta to 0 will disable pre-fetching. + * Setting zoom delta to 0 will disable pre-fetching. * Default zoom delta is 4. * * @param delta zoom delta @@ -926,6 +944,15 @@ public class MapboxMapOptions implements Parcelable { return scrollGesturesEnabled; } + /** + * Get the current configured horizontal scroll gesture state for a map view. + * + * @return True indicates horizontal scroll gesture is enabled + */ + public boolean getHorizontalScrollGesturesEnabled() { + return horizontalScrollGesturesEnabled; + } + /** * Get the current configured tilt gesture state for a map view. * @@ -1108,6 +1135,7 @@ public class MapboxMapOptions implements Parcelable { dest.writeByte((byte) (rotateGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (scrollGesturesEnabled ? 1 : 0)); + dest.writeByte((byte) (horizontalScrollGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (tiltGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (doubleTapGesturesEnabled ? 1 : 0)); @@ -1182,6 +1210,9 @@ public class MapboxMapOptions implements Parcelable { if (scrollGesturesEnabled != options.scrollGesturesEnabled) { return false; } + if (horizontalScrollGesturesEnabled != options.horizontalScrollGesturesEnabled) { + return false; + } if (tiltGesturesEnabled != options.tiltGesturesEnabled) { return false; } @@ -1263,6 +1294,7 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (rotateGesturesEnabled ? 1 : 0); result = 31 * result + (scrollGesturesEnabled ? 1 : 0); + result = 31 * result + (horizontalScrollGesturesEnabled ? 1 : 0); result = 31 * result + (tiltGesturesEnabled ? 1 : 0); result = 31 * result + (zoomGesturesEnabled ? 1 : 0); result = 31 * result + (doubleTapGesturesEnabled ? 1 : 0); diff --git a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index f7bd28eb4..8fb791463 100644 --- a/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -58,6 +58,8 @@ public final class UiSettings { private boolean scrollGesturesEnabled = true; + private boolean horizontalScrollGesturesEnabled = true; + private boolean doubleTapGesturesEnabled = true; private boolean quickZoomGesturesEnabled = true; @@ -117,6 +119,7 @@ public final class UiSettings { private void initialiseGestures(MapboxMapOptions options) { setZoomGesturesEnabled(options.getZoomGesturesEnabled()); setScrollGesturesEnabled(options.getScrollGesturesEnabled()); + setHorizontalScrollGesturesEnabled(options.getHorizontalScrollGesturesEnabled()); setRotateGesturesEnabled(options.getRotateGesturesEnabled()); setTiltGesturesEnabled(options.getTiltGesturesEnabled()); setDoubleTapGesturesEnabled(options.getDoubleTapGesturesEnabled()); @@ -124,6 +127,7 @@ public final class UiSettings { } private void saveGestures(Bundle outState) { + outState.putBoolean(MapboxConstants.STATE_HORIZONAL_SCROLL_ENABLED, isHorizontalScrollGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_ZOOM_ENABLED, isZoomGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_SCROLL_ENABLED, isScrollGesturesEnabled()); outState.putBoolean(MapboxConstants.STATE_ROTATE_ENABLED, isRotateGesturesEnabled()); @@ -140,6 +144,7 @@ public final class UiSettings { } private void restoreGestures(Bundle savedInstanceState) { + setHorizontalScrollGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_HORIZONAL_SCROLL_ENABLED)); setZoomGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ZOOM_ENABLED)); setScrollGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_SCROLL_ENABLED)); setRotateGesturesEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_ROTATE_ENABLED)); @@ -849,6 +854,31 @@ public final class UiSettings { return scrollGesturesEnabled; } + /** + *
+ * Changes whether the user may scroll horizontally around the map. + *
+ *+ * This setting controls only user interactions with the map. If you set the value to false, + * you may still change the map location programmatically. + *
+ * The default value is true. + * + * @param horizontalScrollGesturesEnabled If true, scrolling horizontally is enabled. + */ + public void setHorizontalScrollGesturesEnabled(boolean horizontalScrollGesturesEnabled) { + this.horizontalScrollGesturesEnabled = horizontalScrollGesturesEnabled; + } + + /** + * Returns whether the user may scroll horizontally around the map. + * + * @return If true, scrolling horizontally is enabled. + */ + public boolean isHorizontalScrollGesturesEnabled() { + return horizontalScrollGesturesEnabled; + } + /** * Returns whether scale velocity animation should execute after users finishes a gesture. * diff --git a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 36071cc2a..83c25432d 100644 --- a/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -31,6 +31,7 @@