Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Observe layout guides #7716

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions platform/ios/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed a crash or console spew when MGLMapView is initialized with a frame smaller than 64 points wide by 64 points tall. ([#8562](https://github.com/mapbox/mapbox-gl-native/pull/8562))
* The error passed into `-[MGLMapViewDelegate mapViewDidFailLoadingMap:withError:]` now includes a more specific description and failure reason. ([#8418](https://github.com/mapbox/mapbox-gl-native/pull/8418))
* Fixed an issue rendering polylines that contain duplicate vertices. ([#8808](https://github.com/mapbox/mapbox-gl-native/pull/8808))
* Fixed a bug which caused the compass and other ornaments to underlap navigation and tab bars. ([#7716](https://github.com/mapbox/mapbox-gl-native/pull/7716))

## 3.5.2 - April 7, 2017

Expand Down
218 changes: 104 additions & 114 deletions platform/ios/src/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ typedef NS_ENUM(NSUInteger, MGLUserTrackingState) {

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;

Expand Down Expand Up @@ -233,13 +236,9 @@ @interface MGLMapView () <UIGestureRecognizerDelegate,
@property (nonatomic) GLKView *glView;
@property (nonatomic) UIImageView *glSnapshotView;
@property (nonatomic, readwrite) MGLScaleBar *scaleBar;
@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *scaleBarConstraints;
@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;
Expand Down Expand Up @@ -294,7 +293,8 @@ @implementation MGLMapView
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;

Expand Down Expand Up @@ -471,19 +471,15 @@ - (void)commonInit
_logoView = [[UIImageView alloc] initWithImage:logo];
_logoView.accessibilityTraits = UIAccessibilityTraitStaticText;
_logoView.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"LOGO_A11Y_LABEL", nil, nil, @"Mapbox", @"Accessibility label");
_logoView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_logoView];
_logoViewConstraints = [NSMutableArray array];

// setup attribution
//
_attributionButton = [UIButton buttonWithType:UIButtonTypeInfoLight];
_attributionButton.accessibilityLabel = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_LABEL", nil, nil, @"About this map", @"Accessibility label");
_attributionButton.accessibilityHint = NSLocalizedStringWithDefaultValue(@"INFO_A11Y_HINT", nil, nil, @"Shows credits, a feedback form, and more", @"Accessibility hint");
[_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
Expand All @@ -495,16 +491,12 @@ - (void)commonInit
_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;
[self addSubview:_compassView];
_compassViewConstraints = [NSMutableArray array];

// setup scale control
//
_scaleBar = [[MGLScaleBar alloc] init];
_scaleBar.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_scaleBar];
_scaleBarConstraints = [NSMutableArray array];

// setup interaction
//
Expand Down Expand Up @@ -672,6 +664,14 @@ - (void)dealloc
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_attributionButton removeObserver:self forKeyPath:@"hidden"];

if (_isObservingTopLayoutGuide) {
[(NSObject *)self.viewControllerForLayoutGuides.topLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
}

if (_isObservingBottomLayoutGuide) {
[(NSObject *)self.viewControllerForLayoutGuides.bottomLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
}

// Removing the annotations unregisters any outstanding KVO observers.
NSArray *annotations = self.annotations;
if (annotations)
Expand All @@ -697,11 +697,6 @@ - (void)dealloc
{
[EAGLContext setCurrentContext:nil];
}

[self.logoViewConstraints removeAllObjects];
self.logoViewConstraints = nil;
[self.attributionButtonConstraints removeAllObjects];
self.attributionButtonConstraints = nil;
}

- (void)setDelegate:(nullable id<MGLMapViewDelegate>)delegate
Expand Down Expand Up @@ -786,105 +781,31 @@ - (UIViewController *)viewControllerForLayoutGuides

- (void)updateConstraints
{
// scale control
//
[self removeConstraints:self.scaleBarConstraints];
[self.scaleBarConstraints removeAllObjects];
[super updateConstraints];

[self.scaleBarConstraints addObject:
[NSLayoutConstraint constraintWithItem:self.scaleBar
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:5+self.contentInset.top]];
// 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.scaleBarConstraints addObject:
[NSLayoutConstraint constraintWithItem:self.scaleBar
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeLeading
multiplier:1
constant:8 + self.contentInset.left]];
UIViewController *viewController = self.viewControllerForLayoutGuides;
BOOL useLayoutGuides = viewController.view && viewController.automaticallyAdjustsScrollViewInsets;

[self addConstraints:self.scaleBarConstraints];
if (useLayoutGuides && viewController.topLayoutGuide && !_isObservingTopLayoutGuide) {
[(NSObject *)viewController.topLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext];
_isObservingTopLayoutGuide = YES;
} else if (!useLayoutGuides && _isObservingTopLayoutGuide) {
[(NSObject *)viewController.topLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
_isObservingTopLayoutGuide = NO;
}

// compass
//
[self removeConstraints:self.compassViewConstraints];
[self.compassViewConstraints removeAllObjects];

[self.compassViewConstraints addObject:
[NSLayoutConstraint constraintWithItem:self.compassView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:5 + self.contentInset.top]];

[self.compassViewConstraints addObject:
[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.compassView
attribute:NSLayoutAttributeTrailing
multiplier:1
constant:5 + self.contentInset.right]];

[self addConstraints:self.compassViewConstraints];

// logo bug
//
[self removeConstraints:self.logoViewConstraints];
[self.logoViewConstraints removeAllObjects];

[self.logoViewConstraints addObject:
[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
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
constant:8 + self.contentInset.left]];
[self addConstraints:self.logoViewConstraints];

// attribution button
//
[self removeConstraints:self.attributionButtonConstraints];
[self.attributionButtonConstraints removeAllObjects];

[self.attributionButtonConstraints addObject:
[NSLayoutConstraint constraintWithItem:self
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
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]];
[self addConstraints:self.attributionButtonConstraints];

[super updateConstraints];
if (useLayoutGuides && viewController.bottomLayoutGuide && !_isObservingBottomLayoutGuide) {
[(NSObject *)viewController.bottomLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:(void *)&MGLLayoutGuidesUpdatedContext];
_isObservingBottomLayoutGuide = YES;
} else if (!useLayoutGuides && _isObservingBottomLayoutGuide) {
[(NSObject *)viewController.bottomLayoutGuide removeObserver:self forKeyPath:@"bounds" context:(void *)&MGLLayoutGuidesUpdatedContext];
_isObservingBottomLayoutGuide = NO;
}
}

- (BOOL)isOpaque
Expand Down Expand Up @@ -917,6 +838,10 @@ - (void)layoutSubviews
[super layoutSubviews];

[self adjustContentInset];

[self observeLayoutGuidesIfNeeded];

[self layoutOrnaments];

if (!_isTargetingInterfaceBuilder) {
_mbglMap->setSize([self size]);
Expand All @@ -931,6 +856,39 @@ - (void)layoutSubviews
[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+5,
CGRectGetHeight(self.bounds)-5-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
{
Expand Down Expand Up @@ -970,6 +928,34 @@ - (void)adjustContentInset
self.contentInset = contentInset;
}

- (void)observeLayoutGuidesIfNeeded
{
UIViewController *viewController = self.viewControllerForLayoutGuides;
BOOL useLayoutGuides = viewController.view && viewController.automaticallyAdjustsScrollViewInsets;

if (!_isObservingTopLayoutGuide && useLayoutGuides && viewController.topLayoutGuide)
{
[(NSObject *)viewController.topLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:MGLLayoutGuidesUpdatedContext];
_isObservingTopLayoutGuide = YES;
}
else if (!useLayoutGuides && _isObservingTopLayoutGuide)
{
[(NSObject *)viewController.topLayoutGuide removeObserver:self forKeyPath:@"bounds" context:MGLLayoutGuidesUpdatedContext];
_isObservingTopLayoutGuide = NO;
}

if (!_isObservingBottomLayoutGuide && useLayoutGuides && viewController.bottomLayoutGuide)
{
[(NSObject *)viewController.bottomLayoutGuide addObserver:self forKeyPath:@"bounds" options:0 context:MGLLayoutGuidesUpdatedContext];
_isObservingBottomLayoutGuide = YES;
}
else if (!useLayoutGuides && _isObservingBottomLayoutGuide)
{
[(NSObject *)viewController.bottomLayoutGuide removeObserver:self forKeyPath:@"bounds" context:MGLLayoutGuidesUpdatedContext];
_isObservingBottomLayoutGuide = NO;
}
}

- (void)setContentInset:(UIEdgeInsets)contentInset
{
[self setContentInset:contentInset animated:NO];
Expand Down Expand Up @@ -1000,7 +986,7 @@ - (void)setContentInset:(UIEdgeInsets)contentInset animated:(BOOL)animated
}

// Compass, logo and attribution button constraints needs to be updated.
[self setNeedsUpdateConstraints];
[self setNeedsLayout];
}

/// Returns the frame of inset content within the map view.
Expand Down Expand Up @@ -2065,6 +2051,10 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N
[self updateCalloutView];
}
}
else if (context == MGLLayoutGuidesUpdatedContext && [keyPath isEqualToString:@"bounds"])
{
[self setNeedsLayout];
}
}

+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled
Expand Down
6 changes: 6 additions & 0 deletions platform/ios/src/MGLScaleBar.mm
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ - (void)setMetersPerPoint:(CLLocationDistance)metersPerPoint {

self.row = [self preferredRow];

CGSize size = self.intrinsicContentSize;
self.frame = CGRectMake(CGRectGetMinX(self.frame),
CGRectGetMinY(self.frame),
size.width,
size.height);

[self invalidateIntrinsicContentSize];
[self setNeedsLayout];
}
Expand Down