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

Commit

Permalink
Observe layout guides (#7716)
Browse files Browse the repository at this point in the history
* [ios] observe layout guides

* [ios] update changelog
  • Loading branch information
frederoni authored May 19, 2017
1 parent f4f587f commit 3b109c8
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 114 deletions.
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 @@ -2066,6 +2052,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

0 comments on commit 3b109c8

Please sign in to comment.