diff options
-rw-r--r-- | platform/ios/src/MGLMapView.mm | 318 | ||||
m--------- | platform/ios/uitest/KIF | 0 | ||||
m--------- | platform/ios/uitest/OHHTTPStubs | 0 |
3 files changed, 224 insertions, 94 deletions
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index e056f09d22..08fec00520 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -136,9 +136,6 @@ const CGFloat MGLAnnotationImagePaddingForCallout = 1; const CGSize MGLAnnotationAccessibilityElementMinimumSize = CGSizeMake(10, 10); -// Context for KVO observing UILayoutGuides. -static void * MGLLayoutGuidesUpdatedContext = &MGLLayoutGuidesUpdatedContext; - /// Unique identifier representing a single annotation in mbgl. typedef uint32_t MGLAnnotationTag; @@ -240,10 +237,14 @@ public: @property (nonatomic) EAGLContext *context; @property (nonatomic) GLKView *glView; @property (nonatomic) UIImageView *glSnapshotView; +@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *scaleBarConstraints; @property (nonatomic, readwrite) MGLScaleBar *scaleBar; @property (nonatomic, readwrite) UIImageView *compassView; +@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *compassViewConstraints; @property (nonatomic, readwrite) UIImageView *logoView; +@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints; @property (nonatomic, readwrite) UIButton *attributionButton; +@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints; @property (nonatomic, readwrite) MGLStyle *style; @property (nonatomic) UITapGestureRecognizer *singleTapGestureRecognizer; @property (nonatomic) UITapGestureRecognizer *doubleTap; @@ -298,8 +299,6 @@ public: NSDate *_userLocationAnimationCompletionDate; /// True if a willChange notification has been issued for shape annotation layers and a didChange notification is pending. BOOL _isChangingAnnotationLayers; - BOOL _isObservingTopLayoutGuide; - BOOL _isObservingBottomLayoutGuide; BOOL _isWaitingForRedundantReachableNotification; BOOL _isTargetingInterfaceBuilder; @@ -478,10 +477,12 @@ public: _logoView = [[UIImageView alloc] initWithImage:logo]; _logoView.accessibilityTraits = UIAccessibilityTraitStaticText; _logoView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"LOGO_A11Y_LABEL", nil, nil, @"Mapbox", @"Accessibility label"); + _logoView.translatesAutoresizingMaskIntoConstraints = NO; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 if ([_logoView respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _logoView.accessibilityIgnoresInvertColors = YES; } #endif [self addSubview:_logoView]; + _logoViewConstraints = [NSMutableArray array]; // setup attribution // @@ -492,7 +493,9 @@ public: if ([_attributionButton respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _attributionButton.accessibilityIgnoresInvertColors = YES; } #endif [_attributionButton addTarget:self action:@selector(showAttribution) forControlEvents:UIControlEventTouchUpInside]; + _attributionButton.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_attributionButton]; + _attributionButtonConstraints = [NSMutableArray array]; [_attributionButton addObserver:self forKeyPath:@"hidden" options:NSKeyValueObservingOptionNew context:NULL]; // setup compass @@ -504,18 +507,22 @@ public: _compassView.accessibilityTraits = UIAccessibilityTraitButton; _compassView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"COMPASS_A11Y_LABEL", nil, nil, @"Compass", @"Accessibility label"); _compassView.accessibilityHint = NSLocalizedStringWithDefaultValue(@"COMPASS_A11Y_HINT", nil, nil, @"Rotates the map to face due north", @"Accessibility hint"); + _compassView.translatesAutoresizingMaskIntoConstraints = NO; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 if ([_compassView respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _compassView.accessibilityIgnoresInvertColors = YES; } #endif [self addSubview:_compassView]; + _compassViewConstraints = [NSMutableArray array]; // setup scale control // _scaleBar = [[MGLScaleBar alloc] init]; + _scaleBar.translatesAutoresizingMaskIntoConstraints = NO; #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 if ([_scaleBar respondsToSelector:@selector(accessibilityIgnoresInvertColors)]) { _scaleBar.accessibilityIgnoresInvertColors = YES; } #endif [self addSubview:_scaleBar]; + _scaleBarConstraints = [NSMutableArray array]; // setup interaction // @@ -678,48 +685,6 @@ public: _isWaitingForRedundantReachableNotification = NO; } -- (void)willMoveToWindow:(UIWindow *)newWindow -{ - [super willMoveToWindow:newWindow]; - - if (newWindow) { - [self addLayoutGuideObserversIfNeeded]; - } else { - [self removeLayoutGuideObserversIfNeeded]; - } -} - -- (void)addLayoutGuideObserversIfNeeded -{ - UIViewController *viewController = self.viewControllerForLayoutGuides; - BOOL useLayoutGuides = viewController.view && viewController.automaticallyAdjustsScrollViewInsets; - - if (useLayoutGuides && viewController.topLayoutGuide && !_isObservingTopLayoutGuide) { - [(NSObject *)viewController.topLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext]; - _isObservingTopLayoutGuide = YES; - } - - if (useLayoutGuides && viewController.bottomLayoutGuide && !_isObservingBottomLayoutGuide) { - [(NSObject *)viewController.bottomLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext]; - _isObservingBottomLayoutGuide = YES; - } -} - -- (void)removeLayoutGuideObserversIfNeeded -{ - UIViewController *viewController = self.viewControllerForLayoutGuides; - - if (_isObservingTopLayoutGuide) { - [(NSObject *)viewController.topLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext]; - _isObservingTopLayoutGuide = NO; - } - - if (_isObservingBottomLayoutGuide) { - [(NSObject *)viewController.bottomLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext]; - _isObservingBottomLayoutGuide = NO; - } -} - - (void)dealloc { [_reachability stopNotifier]; @@ -728,8 +693,6 @@ public: [[NSNotificationCenter defaultCenter] removeObserver:self]; [_attributionButton removeObserver:self forKeyPath:@"hidden"]; - [self removeLayoutGuideObserversIfNeeded]; - // Removing the annotations unregisters any outstanding KVO observers. NSArray *annotations = self.annotations; if (annotations) @@ -755,6 +718,18 @@ public: { [EAGLContext setCurrentContext:nil]; } + + [self.compassViewConstraints removeAllObjects]; + self.compassViewConstraints = nil; + + [self.scaleBarConstraints removeAllObjects]; + self.scaleBarConstraints = nil; + + [self.logoViewConstraints removeAllObjects]; + self.logoViewConstraints = nil; + + [self.attributionButtonConstraints removeAllObjects]; + self.attributionButtonConstraints = nil; } - (void)setDelegate:(nullable id<MGLMapViewDelegate>)delegate @@ -781,6 +756,7 @@ public: - (void)setFrame:(CGRect)frame { [super setFrame:frame]; + if ( ! CGRectEqualToRect(frame, self.frame)) { [self validateTileCacheSize]; @@ -790,6 +766,7 @@ public: - (void)setBounds:(CGRect)bounds { [super setBounds:bounds]; + if ( ! CGRectEqualToRect(bounds, self.bounds)) { [self validateTileCacheSize]; @@ -837,15 +814,207 @@ public: return nil; } +- (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 + // + [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:5.0 + self.contentInset.top]]; + } + [self.compassViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.compassView + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:5.0 + self.contentInset.top]]; + [self.compassViewConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:self.compassView + attribute:NSLayoutAttributeTrailing + multiplier:1.0 + constant:5.0 + self.contentInset.right]]; + + [containerView addConstraints:self.compassViewConstraints]; + + // scale bar view + // + [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:5.0 + self.contentInset.top]]; + } + [self.scaleBarConstraints addObject: + [NSLayoutConstraint constraintWithItem:self.scaleBar + attribute:NSLayoutAttributeTop + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self + attribute:NSLayoutAttributeTop + multiplier:1.0 + constant:5.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 + 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 + self.contentInset.bottom]]; + } + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeBottom + relatedBy:NSLayoutRelationGreaterThanOrEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeBaseline + multiplier:1 + constant:8 + self.contentInset.bottom]]; + + [self.attributionButtonConstraints addObject: + [NSLayoutConstraint constraintWithItem:self + attribute:NSLayoutAttributeTrailing + relatedBy:NSLayoutRelationEqual + toItem:self.attributionButton + attribute:NSLayoutAttributeTrailing + multiplier:1 + constant:8 + self.contentInset.right]]; + [containerView addConstraints:self.attributionButtonConstraints]; +} + - (void)updateConstraints { - [super updateConstraints]; - // If we have a view controller reference and its automaticallyAdjustsScrollViewInsets - // is set to YES, -[MGLMapView adjustContentInset] takes top and bottom layout - // guides into account. To get notified about changes to the layout guides, - // we need to observe their bounds and re-layout accordingly. - [self addLayoutGuideObserversIfNeeded]; +// If compiling with the iOS 11+ SDK +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 + // If safeAreaLayoutGuide API exists + if ( [self respondsToSelector:@selector(safeAreaLayoutGuide)] ) { + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpartial-availability" + UILayoutGuide *safeAreaLayoutGuide = self.safeAreaLayoutGuide; +#pragma clang diagnostic pop + // compass view + [self removeConstraints:self.compassViewConstraints]; + [self.compassViewConstraints removeAllObjects]; + [self.compassViewConstraints addObject:[self.compassView.topAnchor constraintEqualToAnchor:safeAreaLayoutGuide.topAnchor + constant:5.0 + self.contentInset.top]]; + [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.scaleBar.topAnchor constraintEqualToAnchor:safeAreaLayoutGuide.topAnchor + constant:5.0 + self.contentInset.top]]; + [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:[safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:self.logoView.bottomAnchor + constant:8.0 + self.contentInset.bottom]]; + [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:[safeAreaLayoutGuide.bottomAnchor constraintEqualToAnchor:self.attributionButton.bottomAnchor + constant:8.0 + self.contentInset.bottom]]; + [self.attributionButtonConstraints addObject:[safeAreaLayoutGuide.rightAnchor constraintEqualToAnchor:self.attributionButton.rightAnchor + constant:8.0 + self.contentInset.right]]; + [self addConstraints:self.attributionButtonConstraints]; + } else { + [self updateConstraintsPreiOS11]; + } +#else + [self updateConstraintsPreiOS11]; +#endif + + [super updateConstraints]; } - (BOOL)isOpaque @@ -878,8 +1047,6 @@ public: [super layoutSubviews]; [self adjustContentInset]; - - [self layoutOrnaments]; if (!_isTargetingInterfaceBuilder) { _mbglMap->setSize([self size]); @@ -898,39 +1065,6 @@ public: [self updateUserLocationAnnotationView]; } -- (void)layoutOrnaments -{ - // scale bar - self.scaleBar.frame = { - self.contentInset.left+8, - self.contentInset.top+5, - CGRectGetWidth(self.scaleBar.frame), - CGRectGetHeight(self.scaleBar.frame) - }; - - // compass - self.compassView.center = { - .x = CGRectGetWidth(self.bounds)-CGRectGetMidX(self.compassView.bounds)-self.contentInset.right-5, - .y = CGRectGetMidY(self.compassView.bounds)+self.contentInset.top+5 - }; - - // logo bug - self.logoView.frame = { - self.contentInset.left+8, - CGRectGetHeight(self.bounds)-8-self.contentInset.bottom-CGRectGetHeight(self.logoView.bounds), - CGRectGetWidth(self.logoView.bounds), - CGRectGetHeight(self.logoView.bounds) - }; - - // attribution - self.attributionButton.frame = { - CGRectGetWidth(self.bounds)-CGRectGetWidth(self.attributionButton.bounds)-self.contentInset.right-8, - CGRectGetHeight(self.bounds)-CGRectGetHeight(self.attributionButton.bounds)-self.contentInset.bottom-8, - CGRectGetWidth(self.attributionButton.bounds), - CGRectGetHeight(self.attributionButton.bounds) - }; -} - /// Updates `contentInset` to reflect the current window geometry. - (void)adjustContentInset { @@ -2090,10 +2224,6 @@ public: [self updateCalloutView]; } } - else if (context == MGLLayoutGuidesUpdatedContext && [keyPath isEqualToString:@"bounds"]) - { - [self setNeedsLayout]; - } } + (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled diff --git a/platform/ios/uitest/KIF b/platform/ios/uitest/KIF -Subproject 973a4cb653b54c3e8b2c0681f4097568ff0ac34 +Subproject c40b1048a6f35c6fd90376846a1a933844516b3 diff --git a/platform/ios/uitest/OHHTTPStubs b/platform/ios/uitest/OHHTTPStubs -Subproject deed01a1592210a4c37f3f5c5f2b32fe0e41c60 +Subproject 4dc6f36375f78c0b3cfe58d90bb8a4e21df5196 |