summaryrefslogtreecommitdiff
path: root/platform/ios/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ios/src')
-rw-r--r--platform/ios/src/MGLMapView.h22
-rw-r--r--platform/ios/src/MGLMapView.mm148
2 files changed, 135 insertions, 35 deletions
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 017ba525c4..8f27adee9e 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -287,6 +287,17 @@ MGL_EXPORT
- (IBAction)reloadStyle:(nullable id)sender;
/**
+ A boolean value that indicates if whether the map view should automatically
+ adjust its content insets.
+
+ When this property is set to `YES` the map automatically updates its
+ `contentInset` property to account for any area not covered by navigation bars,
+ tab bars, toolbars, and other ancestors that obscure the map view.
+
+ */
+@property (assign) BOOL automaticallyAdjustsContentInset;
+
+/**
A Boolean value indicating whether the map may display scale information.
The scale bar may not be shown at all zoom levels. The scale bar becomes visible
@@ -1308,10 +1319,13 @@ MGL_EXPORT
view’s frame. Otherwise, those properties are inset, excluding part of the
frame from the viewport. For instance, if the only the top edge is inset, the
map center is effectively shifted downward.
-
+
When the map view’s superview is an instance of `UIViewController` whose
`automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this
property may be overridden at any time.
+
+ The usage of `automaticallyAdjustsScrollViewInsets` has been deprecated
+ use the map view’s property `MGLMapView.automaticallyAdjustsContentInset`instead.
Changing the value of this property updates the map view immediately. If you
want to animate the change, use the `-setContentInset:animated:completionHandler:`
@@ -1333,6 +1347,9 @@ MGL_EXPORT
`automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this
property may be overridden at any time.
+ The usage of `automaticallyAdjustsScrollViewInsets` has been deprecated
+ use the map view’s property `MGLMapView.automaticallyAdjustsContentInset`instead.
+
To specify a completion handler to execute after the animation finishes, use
the `-setContentInset:animated:completionHandler:` method.
@@ -1357,6 +1374,9 @@ MGL_EXPORT
When the map view’s superview is an instance of `UIViewController` whose
`automaticallyAdjustsScrollViewInsets` property is `YES`, the value of this
property may be overridden at any time.
+
+ The usage of `automaticallyAdjustsScrollViewInsets` has been deprecated
+ use the map view’s property `MGLMapView.automaticallyAdjustsContentInset`instead.
@param contentInset The new values to inset the content by.
@param animated Specify `YES` if you want the map view to animate the change to
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 76cec479bb..9b4ef8ff2d 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -274,6 +274,11 @@ public:
/// Tilt gesture recognizer helper
@property (nonatomic, assign) CGPoint dragGestureMiddlePoint;
+/// This property is used to keep track of the view's safe edge insets
+/// and calculate the ornament's position
+@property (nonatomic, assign) UIEdgeInsets safeMapViewContentInsets;
+@property (nonatomic, strong) NSNumber *automaticallyAdjustContentInsetHolder;
+
- (mbgl::Map &)mbglMap;
@end
@@ -518,6 +523,14 @@ public:
_annotationViewReuseQueueByIdentifier = [NSMutableDictionary dictionary];
_selectedAnnotationTag = MGLAnnotationTagNotFound;
_annotationsNearbyLastTap = {};
+
+ // TODO: This warning should be removed when automaticallyAdjustsScrollViewInsets is removed from
+ // the UIViewController api.
+ static dispatch_once_t onceToken;
+ dispatch_once(&onceToken, ^{
+ NSLog(@"%@ WARNING UIViewController.automaticallyAdjustsScrollViewInsets is deprecated use MGLMapView.automaticallyAdjustContentInset instead.",
+ NSStringFromClass(self.class));
+ });
// setup logo
//
@@ -832,23 +845,46 @@ public:
size:(CGSize)size
margins:(CGPoint)margins {
NSMutableArray *updatedConstraints = [NSMutableArray array];
+ UIEdgeInsets inset = UIEdgeInsetsZero;
+
+ BOOL automaticallyAdjustContentInset;
+ if (_automaticallyAdjustContentInsetHolder) {
+ automaticallyAdjustContentInset = _automaticallyAdjustContentInsetHolder.boolValue;
+ } else {
+ UIViewController *viewController = [self rootViewController];
+ automaticallyAdjustContentInset = viewController.automaticallyAdjustsScrollViewInsets;
+ }
+
+ if (! automaticallyAdjustContentInset) {
+ inset = UIEdgeInsetsMake(self.contentInset.top - self.safeMapViewContentInsets.top,
+ self.contentInset.left - self.safeMapViewContentInsets.left,
+ self.contentInset.bottom - self.safeMapViewContentInsets.bottom,
+ self.contentInset.right - self.safeMapViewContentInsets.right);
+
+ // makes sure the insets don't have negative values that could hide the ornaments
+ // thus violating our ToS
+ inset = UIEdgeInsetsMake(fmaxf(inset.top, 0),
+ fmaxf(inset.left, 0),
+ fmaxf(inset.bottom, 0),
+ fmaxf(inset.right, 0));
+ }
switch (position) {
case MGLOrnamentPositionTopLeft:
- [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y]];
- [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x]];
+ [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y + inset.top]];
+ [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x + inset.left]];
break;
case MGLOrnamentPositionTopRight:
- [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y]];
- [updatedConstraints addObject:[self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x]];
+ [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:margins.y + inset.top]];
+ [updatedConstraints addObject:[self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x + inset.right]];
break;
case MGLOrnamentPositionBottomLeft:
- [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y]];
- [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x]];
+ [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y + inset.bottom]];
+ [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:margins.x + inset.left]];
break;
case MGLOrnamentPositionBottomRight:
- [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y]];
- [updatedConstraints addObject: [self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x]];
+ [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:margins.y + inset.bottom]];
+ [updatedConstraints addObject: [self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:margins.x + inset.right]];
break;
}
@@ -968,6 +1004,38 @@ public:
/// Updates `contentInset` to reflect the current window geometry.
- (void)adjustContentInset
{
+ UIEdgeInsets adjustedContentInsets = UIEdgeInsetsZero;
+ UIViewController *viewController = [self rootViewController];
+ BOOL automaticallyAdjustContentInset;
+ if (@available(iOS 11.0, *))
+ {
+ adjustedContentInsets = self.safeAreaInsets;
+
+ } else {
+ adjustedContentInsets.top = viewController.topLayoutGuide.length;
+ CGFloat bottomPoint = CGRectGetMaxY(viewController.view.bounds) -
+ (CGRectGetMaxY(viewController.view.bounds)
+ - viewController.bottomLayoutGuide.length);
+ adjustedContentInsets.bottom = bottomPoint;
+
+ }
+
+ if (_automaticallyAdjustContentInsetHolder) {
+ automaticallyAdjustContentInset = _automaticallyAdjustContentInsetHolder.boolValue;
+ } else {
+ automaticallyAdjustContentInset = viewController.automaticallyAdjustsScrollViewInsets;
+ }
+
+ self.safeMapViewContentInsets = adjustedContentInsets;
+ if ( ! automaticallyAdjustContentInset)
+ {
+ return;
+ }
+
+ self.contentInset = adjustedContentInsets;
+}
+
+- (UIViewController *)rootViewController {
// We could crawl all the way up the responder chain using
// -viewControllerForLayoutGuides, but an intervening view means that any
// manual contentInset should not be overridden; something other than the
@@ -983,25 +1051,16 @@ public:
// This map view is an immediate child of a view controller’s content view.
viewController = (UIViewController *)self.superview.nextResponder;
}
+ return viewController;
+}
- if ( ! viewController.automaticallyAdjustsScrollViewInsets)
- {
- return;
- }
-
- UIEdgeInsets contentInset = UIEdgeInsetsZero;
- CGPoint topPoint = CGPointMake(0, viewController.topLayoutGuide.length);
- contentInset.top = [self convertPoint:topPoint fromView:viewController.view].y;
- CGPoint bottomPoint = CGPointMake(0, CGRectGetMaxY(viewController.view.bounds)
- - viewController.bottomLayoutGuide.length);
- contentInset.bottom = (CGRectGetMaxY(self.bounds)
- - [self convertPoint:bottomPoint fromView:viewController.view].y);
-
- // Negative insets are invalid, replace with 0.
- contentInset.top = fmaxf(contentInset.top, 0);
- contentInset.bottom = fmaxf(contentInset.bottom, 0);
+- (void)setAutomaticallyAdjustsContentInset:(BOOL)automaticallyAdjustsContentInset {
+ MGLLogDebug(@"Setting automaticallyAdjustsContentInset: %@", MGLStringFromBOOL(automaticallyAdjustsContentInset));
+ _automaticallyAdjustContentInsetHolder = [NSNumber numberWithBool:automaticallyAdjustsContentInset];
+}
- self.contentInset = contentInset;
+- (BOOL)automaticallyAdjustsContentInset {
+ return _automaticallyAdjustContentInsetHolder.boolValue;
}
- (void)setContentInset:(UIEdgeInsets)contentInset
@@ -1701,7 +1760,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
// The gesture recognizer only reports the gesture’s current center
// point, so use the previous center point to anchor the transition.
@@ -1759,7 +1821,10 @@ public:
{
if (drift)
{
- self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(zoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }), MGLDurationFromTimeInterval(duration));
+ self.mbglMap.easeTo(mbgl::CameraOptions()
+ .withZoom(zoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(duration));
}
}
@@ -1824,7 +1889,8 @@ public:
{
self.mbglMap.jumpTo(mbgl::CameraOptions()
.withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}));
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y})
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
}
[self cameraIsChanging];
@@ -1865,7 +1931,8 @@ public:
{
self.mbglMap.easeTo(mbgl::CameraOptions()
.withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }),
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)),
MGLDurationFromTimeInterval(decelerationRate));
[self notifyGestureDidEndWithDrift:YES];
@@ -1993,7 +2060,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(center), MGLDurationFromTimeInterval(MGLAnimationDuration));
+ self.mbglMap.easeTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(center)
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -2031,7 +2101,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
mbgl::ScreenCoordinate center(gesturePoint.x, gesturePoint.y);
- self.mbglMap.easeTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(center), MGLDurationFromTimeInterval(MGLAnimationDuration));
+ self.mbglMap.easeTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(center)
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)), MGLDurationFromTimeInterval(MGLAnimationDuration));
__weak MGLMapView *weakSelf = self;
@@ -2073,7 +2146,10 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
}
[self cameraIsChanging];
@@ -2140,7 +2216,8 @@ public:
{
self.mbglMap.jumpTo(mbgl::CameraOptions()
.withPitch(pitchNew)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
}
[self cameraIsChanging];
@@ -3200,7 +3277,10 @@ public:
centerPoint = self.userLocationAnnotationViewCenter;
}
double newZoom = round(self.zoomLevel) + log2(scaleFactor);
- self.mbglMap.jumpTo(mbgl::CameraOptions().withZoom(newZoom).withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withZoom(newZoom)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y })
+ .withPadding(MGLEdgeInsetsFromNSEdgeInsets(self.contentInset)));
[self unrotateIfNeededForGesture];
_accessibilityValueAnnouncementIsPending = YES;