diff options
Diffstat (limited to 'platform/ios/src/MGLMapView.mm')
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 347 |
1 files changed, 210 insertions, 137 deletions
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 9620a9514c..2c10a606c0 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -54,7 +54,6 @@ #import "UIDevice+MGLAdditions.h" #import "UIImage+MGLAdditions.h" #import "UIViewController+MGLAdditions.h" -#import "UIView+MGLAdditions.h" #import "MGLFaux3DUserLocationAnnotationView.h" #import "MGLUserLocationAnnotationView.h" @@ -97,8 +96,6 @@ const MGLExceptionName MGLUserLocationAnnotationTypeException = @"MGLUserLocatio const MGLExceptionName MGLResourceNotFoundException = @"MGLResourceNotFoundException"; const MGLExceptionName MGLUnderlyingMapUnavailableException = @"MGLUnderlyingMapUnavailableException"; -const CGPoint MGLDefaultOrnamentPositionOffset = CGPointMake(8, 8); - /// 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. @@ -514,8 +511,6 @@ public: _logoView.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_logoView]; _logoViewConstraints = [NSMutableArray array]; - _logoViewPosition = MGLOrnamentPositionBottomLeft; - _logoViewOffset = MGLDefaultOrnamentPositionOffset; // setup attribution // @@ -530,8 +525,6 @@ public: UILongPressGestureRecognizer *attributionLongPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(showAttribution:)]; [_attributionButton addGestureRecognizer:attributionLongPress]; - _attributionButtonPosition = MGLOrnamentPositionBottomRight; - _attributionButtonOffset = MGLDefaultOrnamentPositionOffset; // setup compass // @@ -545,8 +538,6 @@ public: _compassView.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_compassView]; _compassViewConstraints = [NSMutableArray array]; - _compassViewPosition = MGLOrnamentPositionTopRight; - _compassViewOffset = MGLDefaultOrnamentPositionOffset; // setup scale control // @@ -554,11 +545,7 @@ public: _scaleBar.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_scaleBar]; _scaleBarConstraints = [NSMutableArray array]; - _scaleBarPosition = MGLOrnamentPositionTopLeft; - _scaleBarOffset = MGLDefaultOrnamentPositionOffset; - - [self installConstraints]; - + // setup interaction // _pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)]; @@ -812,134 +799,222 @@ public: return YES; } -- (void)setScaleBarPosition:(MGLOrnamentPosition)scaleBarPosition { - MGLLogDebug(@"Setting scaleBarPosition: %lu", scaleBarPosition); - _scaleBarPosition = scaleBarPosition; - [self installScaleBarConstraints]; -} - -- (void)setScaleBarOffset:(CGPoint)scaleBarOffset { - NSAssert(scaleBarOffset.x >= 0 && scaleBarOffset.y >= 0, @"The position offset of the scale bar should not be negative."); - MGLLogDebug(@"Setting scaleBarOffset: (x:%f, y:%f)", scaleBarOffset.x, scaleBarOffset.y); - _scaleBarOffset = scaleBarOffset; - [self installScaleBarConstraints]; -} - -- (void)setCompassViewPosition:(MGLOrnamentPosition)compassViewPosition { - MGLLogDebug(@"Setting compassViewPosition: %lu", compassViewPosition); - _compassViewPosition = compassViewPosition; - [self installCompassViewConstraints]; -} - -- (void)setCompassViewOffset:(CGPoint)compassViewOffset { - NSAssert(compassViewOffset.x >= 0 && compassViewOffset.y >= 0, @"The position offset of the compass should not be negative."); - MGLLogDebug(@"Setting compassViewOffset: (x:%f, y:%f)", compassViewOffset.x, compassViewOffset.y); - _compassViewOffset = compassViewOffset; - [self installCompassViewConstraints]; -} - -- (void)setLogoViewPosition:(MGLOrnamentPosition)logoViewPosition { - MGLLogDebug(@"Setting logoViewPosition: %lu", logoViewPosition); - _logoViewPosition = logoViewPosition; - [self installLogoViewConstraints]; -} - -- (void)setLogoViewOffset:(CGPoint)logoViewOffset { - NSAssert(logoViewOffset.x >= 0 && logoViewOffset.y >= 0, @"The position offset of the logo should not be negative."); - MGLLogDebug(@"Setting logoViewOffset: (x:%f, y:%f)", logoViewOffset.x, logoViewOffset.y); - _logoViewOffset = logoViewOffset; - [self installLogoViewConstraints]; -} - -- (void)setAttributionButtonPosition:(MGLOrnamentPosition)attributionButtonPosition { - MGLLogDebug(@"Setting attributionButtonPosition: %lu", attributionButtonPosition); - _attributionButtonPosition = attributionButtonPosition; - [self installAttributionButtonConstraints]; -} - -- (void)setAttributionButtonOffset:(CGPoint)attributionButtonOffset { - NSAssert(attributionButtonOffset.x >= 0 && attributionButtonOffset.y >= 0, @"The position offset of the attribution should not be negative."); - MGLLogDebug(@"Setting attributionButtonOffset: (x:%f, y:%f)", attributionButtonOffset.x, attributionButtonOffset.y); - _attributionButtonOffset = attributionButtonOffset; - [self installAttributionButtonConstraints]; -} - -- (void)installConstraintsWithView:(UIView *)view - constraints:(NSMutableArray *)constraints - position:(MGLOrnamentPosition)position - size:(CGSize)size - offset:(CGPoint)offset { - NSMutableArray *updatedConstraints = [NSMutableArray array]; - - switch (position) { - case MGLOrnamentPositionTopLeft: - [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:offset.y]]; - [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:offset.x]]; - break; - case MGLOrnamentPositionTopRight: - [updatedConstraints addObject:[view.topAnchor constraintEqualToAnchor:self.mgl_safeTopAnchor constant:offset.y]]; - [updatedConstraints addObject:[self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:offset.x]]; - break; - case MGLOrnamentPositionBottomLeft: - [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:offset.y]]; - [updatedConstraints addObject:[view.leadingAnchor constraintEqualToAnchor:self.mgl_safeLeadingAnchor constant:offset.x]]; - break; - case MGLOrnamentPositionBottomRight: - [updatedConstraints addObject:[self.mgl_safeBottomAnchor constraintEqualToAnchor:view.bottomAnchor constant:offset.y]]; - [updatedConstraints addObject: [self.mgl_safeTrailingAnchor constraintEqualToAnchor:view.trailingAnchor constant:offset.x]]; - break; - default: - break; - } - - [NSLayoutConstraint deactivateConstraints:constraints]; - [constraints removeAllObjects]; - [NSLayoutConstraint activateConstraints:updatedConstraints]; - [constraints addObjectsFromArray:updatedConstraints]; -} - -- (void)installConstraints +- (UIViewController *)viewControllerForLayoutGuides { - [self installCompassViewConstraints]; - [self installScaleBarConstraints]; - [self installLogoViewConstraints]; - [self installAttributionButtonConstraints]; + // Per -[UIResponder nextResponder] documentation, a UIView’s next responder + // is its managing UIViewController if applicable, or otherwise its + // superview. UIWindow’s next responder is UIApplication, which has no next + // responder. + UIResponder *laterResponder = self; + while ([laterResponder isKindOfClass:[UIView class]]) + { + laterResponder = laterResponder.nextResponder; + } + if ([laterResponder isKindOfClass:[UIViewController class]]) + { + return (UIViewController *)laterResponder; + } + return nil; } -- (void)installCompassViewConstraints { +- (void)updateConstraintsPreiOS11 { + // If we have a view controller reference and its automaticallyAdjustsScrollViewInsets + // is set to YES, use its view as the parent for constraints. -[MGLMapView adjustContentInset] + // already take top and bottom layout guides into account. If we don't have a reference, apply + // constraints against ourself to maintain placement of the subviews. + // + UIViewController *viewController = self.viewControllerForLayoutGuides; + BOOL useLayoutGuides = viewController.view && viewController.automaticallyAdjustsScrollViewInsets; + UIView *containerView = useLayoutGuides ? viewController.view : self; + // compass view - [self installConstraintsWithView:self.compassView - constraints:self.compassViewConstraints - position:self.compassViewPosition - size:self.compassView.bounds.size - offset:self.compassViewOffset]; -} - -- (void)installScaleBarConstraints { + // + [containerView removeConstraints:self.compassViewConstraints]; + [self.compassViewConstraints removeAllObjects]; + + if (useLayoutGuides) { + [self.compassViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.compassView + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:viewController.topLayoutGuide + attribute:NSLayoutAttributeBottom + multiplier:1.0 + constant:8.0]]; + } + [self.compassViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.compassView + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:8.0 + self.contentInset.top]]; + + [self.compassViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:self.compassView + attribute:NSLayoutAttributeTrailing + multiplier:1.0 + constant:8.0 + self.contentInset.right]]; + + [containerView addConstraints:self.compassViewConstraints]; + // scale bar view - [self installConstraintsWithView:self.scaleBar - constraints:self.scaleBarConstraints - position:self.scaleBarPosition - size:self.scaleBar.intrinsicContentSize - offset:self.scaleBarOffset]; + // + [containerView removeConstraints:self.scaleBarConstraints]; + [self.scaleBarConstraints removeAllObjects]; + + if (useLayoutGuides) { + [self.scaleBarConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.scaleBar + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:viewController.topLayoutGuide + attribute:NSLayoutAttributeBottom + multiplier:1.0 + constant:8.0]]; + } + [self.scaleBarConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.scaleBar + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:8.0 + self.contentInset.top]]; + [self.scaleBarConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.scaleBar + attribute:NSLayoutAttributeLeft + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeLeft + multiplier:1.0 + constant:8.0 + self.contentInset.left]]; + + [containerView addConstraints:self.scaleBarConstraints]; + + // logo view + // + [containerView removeConstraints:self.logoViewConstraints]; + [self.logoViewConstraints removeAllObjects]; + + if (useLayoutGuides) { + [self.logoViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:viewController.bottomLayoutGuide + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.logoView + attribute:NSLayoutAttributeBaseline + multiplier:1.0 + constant:8.0 + self.contentInset.bottom]]; + } + [self.logoViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.logoView + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8.0 + self.contentInset.bottom]]; + [self.logoViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.logoView + attribute:NSLayoutAttributeLeading + relatedBy:NSLayoutRelationEqual + toItem:self + attribute:NSLayoutAttributeLeading + multiplier:1.0 + constant:8.0 + self.contentInset.left]]; + [containerView addConstraints:self.logoViewConstraints]; + + // attribution button + // + [containerView removeConstraints:self.attributionButtonConstraints]; + [self.attributionButtonConstraints removeAllObjects]; + + if (useLayoutGuides) { + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:viewController.bottomLayoutGuide + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8.0 + self.contentInset.bottom]]; + } + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8.0 + self.contentInset.bottom]]; + + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeTrailing + multiplier:1 + constant:8.0 + self.contentInset.right]]; + [containerView addConstraints:self.attributionButtonConstraints]; } -- (void)installLogoViewConstraints { - // logo view - [self installConstraintsWithView:self.logoView - constraints:self.logoViewConstraints - position:self.logoViewPosition - size:self.logoView.bounds.size - offset:self.logoViewOffset]; +- (void)updateConstraints +{ + // If safeAreaLayoutGuide API exists + if (@available(iOS 11.0, *)) { + UILayoutGuide *safeAreaLayoutGuide = self.safeAreaLayoutGuide; + + // compass view + [self removeConstraints:self.compassViewConstraints]; + [self.compassViewConstraints removeAllObjects]; + [self.compassViewConstraints addObject:[self constraintForYAxisAnchor:self.compassView.topAnchor belowAnchor:safeAreaLayoutGuide.topAnchor]]; + [self.compassViewConstraints addObject:[safeAreaLayoutGuide.rightAnchor constraintEqualToAnchor:self.compassView.rightAnchor + constant:8.0 + self.contentInset.right]]; + [self addConstraints:self.compassViewConstraints]; + + // scale bar view + [self removeConstraints:self.scaleBarConstraints]; + [self.scaleBarConstraints removeAllObjects]; + [self.scaleBarConstraints addObject:[self constraintForYAxisAnchor:self.scaleBar.topAnchor belowAnchor:safeAreaLayoutGuide.topAnchor]]; + [self.scaleBarConstraints addObject:[self.scaleBar.leftAnchor constraintEqualToAnchor:safeAreaLayoutGuide.leftAnchor + constant:8.0 + self.contentInset.left]]; + [self addConstraints:self.scaleBarConstraints]; + + // logo view + [self removeConstraints:self.logoViewConstraints]; + [self.logoViewConstraints removeAllObjects]; + [self.logoViewConstraints addObject:[self constraintForYAxisAnchor:safeAreaLayoutGuide.bottomAnchor belowAnchor:self.logoView.bottomAnchor]]; + [self.logoViewConstraints addObject:[self.logoView.leftAnchor constraintEqualToAnchor:safeAreaLayoutGuide.leftAnchor + constant:8.0 + self.contentInset.left]]; + [self addConstraints:self.logoViewConstraints]; + + // attribution button + [self removeConstraints:self.attributionButtonConstraints]; + [self.attributionButtonConstraints removeAllObjects]; + [self.attributionButtonConstraints addObject:[self constraintForYAxisAnchor:safeAreaLayoutGuide.bottomAnchor belowAnchor:self.attributionButton.bottomAnchor]]; + [self.attributionButtonConstraints addObject:[safeAreaLayoutGuide.rightAnchor constraintEqualToAnchor:self.attributionButton.rightAnchor + constant:8.0 + self.contentInset.right]]; + [self addConstraints:self.attributionButtonConstraints]; + } else { + [self updateConstraintsPreiOS11]; + } + + [super updateConstraints]; } -- (void)installAttributionButtonConstraints { - // attribution button - [self installConstraintsWithView:self.attributionButton - constraints:self.attributionButtonConstraints - position:self.attributionButtonPosition - size:self.attributionButton.bounds.size - offset:self.attributionButtonOffset]; +- (NSLayoutConstraint *)constraintForYAxisAnchor:(NSLayoutYAxisAnchor *)yAxisAnchor belowAnchor:(NSLayoutYAxisAnchor *)anchor +{ + if (@available(iOS 11.0, *)) { + return [yAxisAnchor constraintEqualToSystemSpacingBelowAnchor:anchor multiplier:1]; + } else { + return nil; + } } - (BOOL)isOpaque @@ -1064,7 +1139,7 @@ public: } // Compass, logo and attribution button constraints needs to be updated. - [self installConstraints]; + [self setNeedsUpdateConstraints]; } /// Returns the frame of inset content within the map view. @@ -1221,7 +1296,6 @@ public: - (void)didMoveToSuperview { [self validateDisplayLink]; - [self installConstraints]; [super didMoveToSuperview]; } @@ -2506,7 +2580,7 @@ public: - (CGRect)accessibilityFrame { CGRect frame = [super accessibilityFrame]; - UIViewController *viewController = self.mgl_viewControllerForLayoutGuides; + UIViewController *viewController = self.viewControllerForLayoutGuides; if (viewController) { CGFloat topInset = viewController.topLayoutGuide.length; @@ -6308,7 +6382,6 @@ public: if ( ! self.scaleBar.hidden) { [(MGLScaleBar *)self.scaleBar setMetersPerPoint:[self metersPerPointAtLatitude:self.centerCoordinate.latitude]]; - [self installScaleBarConstraints]; } } |