[android] improve rotation inertia, adjust velocity ratios for screen density
This commit is contained in:
committed by
Łukasz Paczos
parent
3e73e4d49f
commit
acc6079b08
@@ -73,11 +73,6 @@ public class MapboxConstants {
|
||||
*/
|
||||
public static final long VELOCITY_THRESHOLD_IGNORE_FLING = 1000;
|
||||
|
||||
/**
|
||||
* Value by which the default rotation threshold will be increased when scaling
|
||||
*/
|
||||
public static final float ROTATION_THRESHOLD_INCREASE_WHEN_SCALING = 25f;
|
||||
|
||||
/**
|
||||
* Maximum absolute zoom change for multi-pointer scale velocity animation
|
||||
*/
|
||||
@@ -88,20 +83,25 @@ public class MapboxConstants {
|
||||
*/
|
||||
public static final double SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER = 150;
|
||||
|
||||
/**
|
||||
* Last scale span delta to XY velocity ratio required to execute scale velocity animation.
|
||||
*/
|
||||
public static final double SCALE_VELOCITY_RATIO_THRESHOLD = 4 * 1e-3;
|
||||
|
||||
/**
|
||||
* Last rotation delta to XY velocity ratio required to execute rotation velocity animation.
|
||||
*/
|
||||
public static final double ROTATE_VELOCITY_RATIO_THRESHOLD = 2.2 * 1e-4;
|
||||
|
||||
/**
|
||||
* Time within which user needs to lift fingers for velocity animation to start.
|
||||
*/
|
||||
public static final long SCHEDULED_ANIMATION_TIMEOUT = 150L;
|
||||
|
||||
/**
|
||||
* Minimum angular velocity for rotation animation
|
||||
*/
|
||||
public static final float MINIMUM_ANGULAR_VELOCITY = 1.5f;
|
||||
|
||||
/**
|
||||
* Maximum angular velocity for rotation animation
|
||||
*/
|
||||
public static final float MAXIMUM_ANGULAR_VELOCITY = 20f;
|
||||
public static final float MAXIMUM_ANGULAR_VELOCITY = 30f;
|
||||
|
||||
/**
|
||||
* Factor to calculate tilt change based on pixel change during shove gesture.
|
||||
|
||||
@@ -29,8 +29,11 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAXIMUM_ANGULAR_VELOCITY;
|
||||
import static com.mapbox.mapboxsdk.constants.MapboxConstants.MAX_ABSOLUTE_SCALE_VELOCITY_CHANGE;
|
||||
import static com.mapbox.mapboxsdk.constants.MapboxConstants.ROTATE_VELOCITY_RATIO_THRESHOLD;
|
||||
import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER;
|
||||
import static com.mapbox.mapboxsdk.constants.MapboxConstants.SCALE_VELOCITY_RATIO_THRESHOLD;
|
||||
import static com.mapbox.mapboxsdk.constants.MapboxConstants.ZOOM_RATE;
|
||||
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE;
|
||||
|
||||
@@ -114,11 +117,14 @@ final class MapGestureDetector {
|
||||
com.mapbox.android.gestures.R.dimen.mapbox_defaultScaleSpanSinceStartThreshold));
|
||||
MoveGestureListener moveGestureListener = new MoveGestureListener();
|
||||
ScaleGestureListener scaleGestureListener = new ScaleGestureListener(
|
||||
context.getResources().getDimension(R.dimen.mapbox_density_constant),
|
||||
context.getResources().getDimension(R.dimen.mapbox_minimum_scale_speed),
|
||||
context.getResources().getDimension(R.dimen.mapbox_minimum_angled_scale_speed),
|
||||
context.getResources().getDimension(R.dimen.mapbox_minimum_scale_velocity)
|
||||
);
|
||||
RotateGestureListener rotateGestureListener = new RotateGestureListener(
|
||||
context.getResources().getDimension(R.dimen.mapbox_density_constant),
|
||||
context.getResources().getDimension(R.dimen.mapbox_angular_velocity_multiplier),
|
||||
context.getResources().getDimension(R.dimen.mapbox_minimum_angular_velocity));
|
||||
ShoveGestureListener shoveGestureListener = new ShoveGestureListener();
|
||||
TapGestureListener tapGestureListener = new TapGestureListener();
|
||||
@@ -258,7 +264,7 @@ final class MapGestureDetector {
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedules a velocity animator to be executed when user lift fingers,
|
||||
* Schedules a velocity animator to be executed when user lifts fingers,
|
||||
* unless canceled by the {@link #cancelAnimatorsRunnable}.
|
||||
*
|
||||
* @param animator animator ot be scheduled
|
||||
@@ -483,12 +489,16 @@ final class MapGestureDetector {
|
||||
private final float minimumGestureSpeed;
|
||||
private final float minimumAngledGestureSpeed;
|
||||
private final float minimumVelocity;
|
||||
private final double scaleVelocityRatioThreshold;
|
||||
private boolean quickZoom;
|
||||
private float spanSinceLast;
|
||||
|
||||
ScaleGestureListener(float minimumGestureSpeed, float minimumAngledGestureSpeed, float minimumVelocity) {
|
||||
ScaleGestureListener(double densityMultiplier, float minimumGestureSpeed, float minimumAngledGestureSpeed,
|
||||
float minimumVelocity) {
|
||||
this.minimumGestureSpeed = minimumGestureSpeed;
|
||||
this.minimumAngledGestureSpeed = minimumAngledGestureSpeed;
|
||||
this.minimumVelocity = minimumVelocity;
|
||||
this.scaleVelocityRatioThreshold = SCALE_VELOCITY_RATIO_THRESHOLD * densityMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -539,6 +549,8 @@ final class MapGestureDetector {
|
||||
|
||||
notifyOnScaleBeginListeners(detector);
|
||||
|
||||
spanSinceLast = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -554,6 +566,8 @@ final class MapGestureDetector {
|
||||
|
||||
notifyOnScaleListeners(detector);
|
||||
|
||||
spanSinceLast = Math.abs(detector.getCurrentSpan() - detector.getPreviousSpan());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -571,7 +585,9 @@ final class MapGestureDetector {
|
||||
|
||||
float velocityXY = Math.abs(velocityX) + Math.abs(velocityY);
|
||||
|
||||
if (!uiSettings.isScaleVelocityAnimationEnabled() || velocityXY < minimumVelocity) {
|
||||
if (!uiSettings.isScaleVelocityAnimationEnabled()
|
||||
|| velocityXY < minimumVelocity
|
||||
|| spanSinceLast / velocityXY < scaleVelocityRatioThreshold) {
|
||||
// notifying listeners that camera is idle only if there is no follow-up animation
|
||||
dispatchCameraIdle();
|
||||
return;
|
||||
@@ -625,10 +641,14 @@ final class MapGestureDetector {
|
||||
}
|
||||
|
||||
private final class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
|
||||
private final float angularVelocityMultiplier;
|
||||
private final float minimumAngularVelocity;
|
||||
private final double rotateVelocityRatioThreshold;
|
||||
|
||||
RotateGestureListener(float minimumAngularVelocity) {
|
||||
RotateGestureListener(double densityMultiplier, float angularVelocityMultiplier, float minimumAngularVelocity) {
|
||||
this.angularVelocityMultiplier = angularVelocityMultiplier;
|
||||
this.minimumAngularVelocity = minimumAngularVelocity;
|
||||
this.rotateVelocityRatioThreshold = ROTATE_VELOCITY_RATIO_THRESHOLD * densityMultiplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -685,24 +705,23 @@ final class MapGestureDetector {
|
||||
float velocityY, float angularVelocity) {
|
||||
notifyOnRotateEndListeners(detector);
|
||||
|
||||
if (!uiSettings.isRotateVelocityAnimationEnabled() || Math.abs(angularVelocity) < minimumAngularVelocity) {
|
||||
angularVelocity = angularVelocity * angularVelocityMultiplier;
|
||||
angularVelocity = MathUtils.clamp(angularVelocity, -MAXIMUM_ANGULAR_VELOCITY, MAXIMUM_ANGULAR_VELOCITY);
|
||||
|
||||
float velocityXY = Math.abs(velocityX) + Math.abs(velocityY);
|
||||
float delta = Math.abs(detector.getDeltaSinceLast());
|
||||
double ratio = delta / velocityXY;
|
||||
|
||||
if (!uiSettings.isRotateVelocityAnimationEnabled()
|
||||
|| Math.abs(angularVelocity) < minimumAngularVelocity
|
||||
|| (gesturesManager.getStandardScaleGestureDetector().isInProgress() && ratio < rotateVelocityRatioThreshold)) {
|
||||
// notifying listeners that camera is idle only if there is no follow-up animation
|
||||
dispatchCameraIdle();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean negative = angularVelocity < 0;
|
||||
angularVelocity = (float) Math.pow(angularVelocity, 2);
|
||||
angularVelocity = MathUtils.clamp(
|
||||
angularVelocity, MapboxConstants.MINIMUM_ANGULAR_VELOCITY, MapboxConstants.MAXIMUM_ANGULAR_VELOCITY);
|
||||
|
||||
long animationTime = (long) (Math.log(angularVelocity + 1) * 500);
|
||||
|
||||
if (negative) {
|
||||
angularVelocity = -angularVelocity;
|
||||
}
|
||||
|
||||
// todo clear scale velocity if angular velocity exceeds a threshold
|
||||
long animationTime = (long) ((Math.log((Math.abs(angularVelocity)) + 1 / Math.pow(Math.E, 2)) + 2)
|
||||
* SCALE_VELOCITY_ANIMATION_DURATION_MULTIPLIER);
|
||||
|
||||
PointF focalPoint = getRotateFocalPoint(detector);
|
||||
rotateAnimator = createRotateAnimator(angularVelocity, animationTime, focalPoint);
|
||||
@@ -929,10 +948,6 @@ final class MapGestureDetector {
|
||||
&& (!uiSettings.isTiltGesturesEnabled() || !gesturesManager.getShoveGestureDetector().isInProgress());
|
||||
}
|
||||
|
||||
private boolean isZoomValid(double mapZoom) {
|
||||
return mapZoom >= MapboxConstants.MINIMUM_ZOOM && mapZoom <= MapboxConstants.MAXIMUM_ZOOM;
|
||||
}
|
||||
|
||||
void notifyOnMapClickListeners(@NonNull PointF tapPoint) {
|
||||
for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) {
|
||||
if (listener.onMapClick(projection.fromScreenLocation(tapPoint))) {
|
||||
|
||||
@@ -13,7 +13,13 @@
|
||||
<dimen name="mapbox_minimum_scale_velocity">225dp</dimen>
|
||||
|
||||
<!--Minimum angular velocity required to start rotation animation-->
|
||||
<dimen name="mapbox_minimum_angular_velocity">0.025dp</dimen>
|
||||
<dimen name="mapbox_minimum_angular_velocity">0.10dp</dimen>
|
||||
|
||||
<!--Angular velocity multiplier. Adapts the velocity for screen density-->
|
||||
<dimen name="mapbox_angular_velocity_multiplier">1.3dp</dimen>
|
||||
|
||||
<!--Screen density constant to adjust gesture's velocityXY thresholds-->
|
||||
<dimen name="mapbox_density_constant">0.29dp</dimen>
|
||||
|
||||
<dimen name="mapbox_locationComponentTrackingInitialMoveThreshold">25dp</dimen>
|
||||
<dimen name="mapbox_locationComponentTrackingMultiFingerMoveThreshold">400dp</dimen>
|
||||
|
||||
Reference in New Issue
Block a user