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:
Minh Nguyễn
2016-06-29 15:48:02 -07:00
committed by GitHub
parent f7b646cac5
commit 5389f04da5
4 changed files with 41 additions and 13 deletions

View File

@@ -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))

View File

@@ -21,6 +21,9 @@ custom_categories:
- MGLMapCamera
- MGLMapDebugMaskOptions
- MGLMapView
- MGLMapViewDecelerationRateFast
- MGLMapViewDecelerationRateImmediate
- MGLMapViewDecelerationRateNormal
- MGLMapViewDelegate
- MGLStyle
- MGLStyleDefaultVersion

View File

@@ -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
/**

View File

@@ -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];
}];