diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 8d3baa335e..78f313dd65 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,6 +2,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. +## Master + +* Added `MGLMapView.maximumWidthRatio` property for customizing the width ratio of map view's scale bar. ([#65](https://github.com/mapbox/mapbox-gl-native-ios/pull/65)) + ## 5.7.0 - February 13, 2020 ### Bug fixes diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index e13fb01b04..1b3e409efb 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -338,6 +338,13 @@ MGL_EXPORT */ @property (nonatomic, assign) CGPoint scaleBarMargins; +/** + The maximum width ratio of the scale bar relative to the map view's frame. + This value is limited from 0.1 to 1. + Default is 0.5(half of map view's width). + */ +@property (nonatomic, assign) CGFloat scaleBarMaximumWidthRatio; + /** A control indicating the map’s direction and allowing the user to manipulate the direction, positioned in the upper-right corner. diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index d6b35c1916..b7b6ae20cb 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -581,6 +581,7 @@ - (void)commonInit _scaleBarConstraints = [NSMutableArray array]; _scaleBarPosition = MGLOrnamentPositionTopLeft; _scaleBarMargins = MGLOrnamentDefaultPositionOffset; + _scaleBar.margins = MGLOrnamentDefaultPositionOffset; [self installConstraints]; @@ -806,9 +807,22 @@ - (void)setScaleBarPosition:(MGLOrnamentPosition)scaleBarPosition { - (void)setScaleBarMargins:(CGPoint)scaleBarMargins { MGLLogDebug(@"Setting scaleBarMargins: (x:%f, y:%f)", scaleBarMargins.x, scaleBarMargins.y); _scaleBarMargins = scaleBarMargins; + if([self.scaleBar isKindOfClass:[MGLScaleBar class]]) { + ((MGLScaleBar *)self.scaleBar).margins = scaleBarMargins; + } [self installScaleBarConstraints]; } +- (void)setScaleBarMaximumWidthRatio:(CGFloat)scaleBarMaximumWidthRatio { + MGLLogDebug(@"Setting scale bar maximum width ratio: %f", scaleBarMaximumWidthRatio); + _scaleBarMaximumWidthRatio = scaleBarMaximumWidthRatio; + if([self.scaleBar isKindOfClass:[MGLScaleBar class]]) { + ((MGLScaleBar *)self.scaleBar).maximumWidthRatio = scaleBarMaximumWidthRatio; + [(MGLScaleBar *)self.scaleBar setNeedsRecalculateSize]; + } + [self updateScaleBar]; +} + - (void)setCompassViewPosition:(MGLOrnamentPosition)compassViewPosition { MGLLogDebug(@"Setting compassViewPosition: %lu", compassViewPosition); _compassViewPosition = compassViewPosition; @@ -1004,6 +1018,7 @@ - (void)layoutSubviews // `_mbglMap->setSize()` just below that triggers rendering update which triggers // another scale bar update which causes a rendering update loop and a major performace // degradation. + [(MGLScaleBar *)self.scaleBar setNeedsRecalculateSize]; [self.scaleBar invalidateIntrinsicContentSize]; [self adjustContentInset]; diff --git a/platform/ios/src/MGLScaleBar.h b/platform/ios/src/MGLScaleBar.h index 77fd6736b5..0016b4273e 100644 --- a/platform/ios/src/MGLScaleBar.h +++ b/platform/ios/src/MGLScaleBar.h @@ -6,4 +6,15 @@ // Sets the scale and redraws the scale bar @property (nonatomic, assign) CLLocationDistance metersPerPoint; +/* + The maximum width ratio of the scale bar relative to the map view's frame. + This value is limited from 0.1 to 1. + Default is 0.5(half of map view's width). + */ +@property (nonatomic, assign) CGFloat maximumWidthRatio; + +@property (nonatomic, assign) CGPoint margins; + +- (void)setNeedsRecalculateSize; + @end diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm index 3efa80013f..ed38378cfa 100644 --- a/platform/ios/src/MGLScaleBar.mm +++ b/platform/ios/src/MGLScaleBar.mm @@ -142,6 +142,7 @@ - (instancetype)initWithFrame:(CGRect)frame { - (void)commonInit { _size = CGSizeZero; + _maximumWidthRatio = 0.5; _primaryColor = [UIColor colorWithRed:18.0/255.0 green:45.0/255.0 blue:17.0/255.0 alpha:1]; _secondaryColor = [UIColor colorWithRed:247.0/255.0 green:247.0/255.0 blue:247.0/255.0 alpha:1]; @@ -229,7 +230,25 @@ - (CGFloat)actualWidth { - (CGFloat)maximumWidth { // TODO: Consider taking Scale Bar margins into account here. CGFloat fullWidth = CGRectGetWidth(self.superview.bounds); - return floorf(fullWidth / 2); + + if(self.maximumWidthRatio < 0.1) { + self.maximumWidthRatio = 0.1; + } + else if (self.maximumWidthRatio > 1) { + self.maximumWidthRatio = 1; + } + + CGFloat result = floorf(fullWidth * self.maximumWidthRatio); + return result > fullWidth - (self.margins.x * 2) ? fullWidth - (self.margins.x * 2) : result; +} + +- (void)setMaximumWidthRatio:(CGFloat)maximumWidthRatio { + _maximumWidthRatio = maximumWidthRatio; + + [self updateVisibility]; + + self.recalculateSize = YES; + [self invalidateIntrinsicContentSize]; } - (CGFloat)unitsPerPoint { @@ -297,6 +316,12 @@ - (void)setMetersPerPoint:(CLLocationDistance)metersPerPoint { [self invalidateIntrinsicContentSize]; } +- (void)setNeedsRecalculateSize { + self.recalculateSize = YES; + [self setNeedsUpdateConstraints]; + [self updateConstraintsIfNeeded]; +} + - (CGSize)intrinsicContentSize { // Size is calculated elsewhere - since intrinsicContentSize is part of the // constraint system, this should be done in updateConstraints diff --git a/platform/ios/test/MGLMapViewScaleBarTests.m b/platform/ios/test/MGLMapViewScaleBarTests.m index b4f81ef62b..5cc64a2d01 100644 --- a/platform/ios/test/MGLMapViewScaleBarTests.m +++ b/platform/ios/test/MGLMapViewScaleBarTests.m @@ -58,7 +58,7 @@ - (void)testDirectlySettingScaleBarViewHiddenProperty { // ... but triggering any camera event will update it. self.mapView.zoomLevel = 1; [self.mapView layoutIfNeeded]; - + XCTAssertTrue(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); XCTAssertEqual(scaleBar.alpha, 0); @@ -67,4 +67,38 @@ - (void)testDirectlySettingScaleBarViewHiddenProperty { XCTAssertGreaterThan(scaleBar.alpha, 0); XCTAssertFalse(CGSizeEqualToSize(scaleBar.intrinsicContentSize, CGSizeZero)); -}@end +} + +- (void)testScaleBarSizeChanged { + + // The bar maximum bar width can only limit the bar's total width. + // Sometimes we should include some space for last label width, the maximum last label width is 30. + // We add this hint value to avoid testing failed when need a extra space for last label. + CGFloat scaleBarLastLabelWidthHint = 30.0f; + + self.mapView.scaleBarMaximumWidthRatio = 0.5; + UIView *scaleBar = self.mapView.scaleBar; + scaleBar.hidden = NO; + + self.mapView.zoomLevel = 15; + [self.mapView layoutIfNeeded]; + + XCTAssertLessThanOrEqual(scaleBar.intrinsicContentSize.width, self.mapView.frame.size.width/2 + scaleBarLastLabelWidthHint); + + self.mapView.zoomLevel = 10; + [self.mapView layoutIfNeeded]; + XCTAssertLessThanOrEqual(scaleBar.intrinsicContentSize.width, self.mapView.frame.size.width/2 + scaleBarLastLabelWidthHint); + + CGRect frame = self.mapView.frame; + frame.size = CGSizeMake(frame.size.width/2, frame.size.height); + self.mapView.frame = frame; + [self.mapView layoutIfNeeded]; + + XCTAssertLessThanOrEqual(scaleBar.intrinsicContentSize.width, self.mapView.frame.size.width/2 + scaleBarLastLabelWidthHint); + + self.mapView.scaleBarMaximumWidthRatio = 0.3; + + XCTAssertLessThanOrEqual(scaleBar.intrinsicContentSize.width, self.mapView.frame.size.width * 0.3 + scaleBarLastLabelWidthHint); +} + +@end