Adjustable map deceleration rate (#5504)
* [ios] Adds the ability to customize map deceleration speed * [ios] Made pinch, rotation deceleration adjustable too Drift zooming and drift rotation also respect the deceleration rate. A side effect of this change is that drift zooming will come to a stop ever-so-slightly sooner now. * [ios] Documented deceleration rates Added documentation for deceleration rate constants. Also updated the changelog.
This commit is contained in:
@@ -15,6 +15,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CON
|
||||
- `MGLOfflinePackProgress` now indicates how many tiles have been downloaded and how much space they take up. ([#4874](https://github.com/mapbox/mapbox-gl-native/pull/4874))
|
||||
- The compass, user dot, and visible annotations are now accessible to VoiceOver users. ([#1496](https://github.com/mapbox/mapbox-gl-native/pull/1496))
|
||||
- Added a method to MGLMapView, `-anchorPointForGesture:`, that you can override to anchor gestures at a point other than the user location. ([#5302](https://github.com/mapbox/mapbox-gl-native/pull/5302))
|
||||
- Added a property to MGLMapView, `decelerationRate`, that allows you to speed up or slow down the drift animation at the end of a user gesture. You can also use this property to disable the drift animation entirely. ([#5504](https://github.com/mapbox/mapbox-gl-native/pull/5504))
|
||||
- Fixed an issue (speculatively) where the tile cache could be included in iCloud backups. ([#5124](https://github.com/mapbox/mapbox-gl-native/pull/5124))
|
||||
- Improved performance viewing regions with large landcover polygons when viewing a style that uses the Mapbox Streets source. ([#2444](https://github.com/mapbox/mapbox-gl-native/pull/2444))
|
||||
- Fixed a memory leak when using raster resources. ([#5141](https://github.com/mapbox/mapbox-gl-native/pull/5141))
|
||||
|
||||
@@ -21,6 +21,9 @@ custom_categories:
|
||||
- MGLMapCamera
|
||||
- MGLMapDebugMaskOptions
|
||||
- MGLMapView
|
||||
- MGLMapViewDecelerationRateFast
|
||||
- MGLMapViewDecelerationRateImmediate
|
||||
- MGLMapViewDecelerationRateNormal
|
||||
- MGLMapViewDelegate
|
||||
- MGLStyle
|
||||
- MGLStyleDefaultVersion
|
||||
|
||||
@@ -21,6 +21,15 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@protocol MGLCalloutView;
|
||||
@protocol MGLFeature;
|
||||
|
||||
/** The default deceleration rate for a map view. */
|
||||
extern const CGFloat MGLMapViewDecelerationRateNormal;
|
||||
|
||||
/** A fast deceleration rate for a map view. */
|
||||
extern const CGFloat MGLMapViewDecelerationRateFast;
|
||||
|
||||
/** Disables decleration in a map view. */
|
||||
extern const CGFloat MGLMapViewDecelerationRateImmediate;
|
||||
|
||||
/** The vertical alignment of an annotation within a map view. */
|
||||
typedef NS_ENUM(NSUInteger, MGLAnnotationVerticalAlignment) {
|
||||
/** Aligns the annotation vertically in the center of the map view. */
|
||||
@@ -404,6 +413,17 @@ IB_DESIGNABLE
|
||||
*/
|
||||
@property(nonatomic, getter=isPitchEnabled) BOOL pitchEnabled;
|
||||
|
||||
/**
|
||||
A floating-point value that determines the rate of deceleration after the user
|
||||
lifts their finger.
|
||||
|
||||
Your application can use the `MGLMapViewDecelerationRateNormal` and
|
||||
`MGLMapViewDecelerationRateFast` constants as reference points for reasonable
|
||||
deceleration rates. `MGLMapViewDecelerationRateImmediate` can be used to
|
||||
disable deceleration entirely.
|
||||
*/
|
||||
@property(nonatomic) CGFloat decelerationRate;
|
||||
|
||||
#pragma mark Manipulating the Viewpoint
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
class MBGLView;
|
||||
class MGLAnnotationContext;
|
||||
|
||||
const CGFloat MGLMapViewDecelerationRateNormal = UIScrollViewDecelerationRateNormal;
|
||||
const CGFloat MGLMapViewDecelerationRateFast = UIScrollViewDecelerationRateFast;
|
||||
const CGFloat MGLMapViewDecelerationRateImmediate = 0.0;
|
||||
|
||||
/// Indicates the manner in which the map view is tracking the user location.
|
||||
typedef NS_ENUM(NSUInteger, MGLUserTrackingState) {
|
||||
/// The map view is not yet tracking the user location.
|
||||
@@ -500,6 +504,8 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
[self addGestureRecognizer:_twoFingerDrag];
|
||||
_pitchEnabled = YES;
|
||||
|
||||
_decelerationRate = MGLMapViewDecelerationRateNormal;
|
||||
|
||||
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
|
||||
{
|
||||
_quickZoom = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleQuickZoomGesture:)];
|
||||
@@ -1202,18 +1208,17 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
else if (pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateCancelled)
|
||||
{
|
||||
CGPoint velocity = [pan velocityInView:pan.view];
|
||||
if (sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) < 100)
|
||||
if (self.decelerationRate == MGLMapViewDecelerationRateImmediate || sqrtf(velocity.x * velocity.x + velocity.y * velocity.y) < 100)
|
||||
{
|
||||
// Not enough velocity to overcome friction
|
||||
velocity = CGPointZero;
|
||||
}
|
||||
|
||||
NSTimeInterval duration = UIScrollViewDecelerationRateNormal;
|
||||
BOOL drift = ! CGPointEqualToPoint(velocity, CGPointZero);
|
||||
if (drift)
|
||||
{
|
||||
CGPoint offset = CGPointMake(velocity.x * duration / 4, velocity.y * duration / 4);
|
||||
_mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSeconds(duration));
|
||||
CGPoint offset = CGPointMake(velocity.x * self.decelerationRate / 4, velocity.y * self.decelerationRate / 4);
|
||||
_mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSeconds(self.decelerationRate));
|
||||
}
|
||||
|
||||
[self notifyGestureDidEndWithDrift:drift];
|
||||
@@ -1283,7 +1288,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
velocity = 0;
|
||||
}
|
||||
|
||||
NSTimeInterval duration = velocity > 0 ? 1 : 0.25;
|
||||
NSTimeInterval duration = (velocity > 0 ? 1 : 0.25) * self.decelerationRate;
|
||||
|
||||
CGFloat scale = self.scale * pinch.scale;
|
||||
CGFloat newScale = scale;
|
||||
@@ -1301,12 +1306,12 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
velocity = 0;
|
||||
}
|
||||
|
||||
if (velocity)
|
||||
if (velocity && duration)
|
||||
{
|
||||
_mbglMap->setScale(newScale, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSeconds(duration));
|
||||
}
|
||||
|
||||
[self notifyGestureDidEndWithDrift:velocity];
|
||||
[self notifyGestureDidEndWithDrift:velocity && duration];
|
||||
|
||||
[self unrotateIfNeededForGesture];
|
||||
}
|
||||
@@ -1355,21 +1360,20 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
|
||||
{
|
||||
CGFloat velocity = rotate.velocity;
|
||||
|
||||
if (fabs(velocity) > 3)
|
||||
CGFloat decelerationRate = self.decelerationRate;
|
||||
if (decelerationRate != MGLMapViewDecelerationRateImmediate && fabs(velocity) > 3)
|
||||
{
|
||||
CGFloat radians = self.angle + rotate.rotation;
|
||||
NSTimeInterval duration = UIScrollViewDecelerationRateNormal;
|
||||
CGFloat newRadians = radians + velocity * duration * 0.1;
|
||||
CGFloat newRadians = radians + velocity * decelerationRate * 0.1;
|
||||
CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1;
|
||||
|
||||
_mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSeconds(duration));
|
||||
_mbglMap->setBearing(newDegrees, mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }, MGLDurationInSeconds(decelerationRate));
|
||||
|
||||
[self notifyGestureDidEndWithDrift:YES];
|
||||
|
||||
__weak MGLMapView *weakSelf = self;
|
||||
|
||||
[self animateWithDelay:duration animations:^
|
||||
[self animateWithDelay:decelerationRate animations:^
|
||||
{
|
||||
[weakSelf unrotateIfNeededForGesture];
|
||||
}];
|
||||
|
||||
Reference in New Issue
Block a user