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

[ios] Scale bar #7631

Merged
merged 12 commits into from
Apr 16, 2017
Merged

[ios] Scale bar #7631

merged 12 commits into from
Apr 16, 2017

Conversation

frederoni
Copy link
Contributor

@frederoni frederoni commented Jan 8, 2017

Fixes #1278 

This PR adds a ~~~distance formatter and~~~ scale bar.

![cropped](https://cloud.githubusercontent.com/assets/764476/24864982/2fd3739a-1e06-11e7-80b1-31193da263e1.gif)


Todo:
- [x] Expose a `scaleBar` property on the map view so user can hide the scale bar.
- [x] Test on all devices.
- [x] Mirror layout in case of right-to-left.
- [x] Rename to `MGLScaleBar`

@mention-bot
Copy link

@frederoni, thanks for your PR! By analyzing this pull request, we identified @incanus, @1ec5 and @boundsj to be potential reviewers.

This was referenced Jan 8, 2017
@frederoni frederoni added iOS Mapbox Maps SDK for iOS macOS Mapbox Maps SDK for macOS MapKit parity For feature parity with MapKit on iOS or macOS labels Jan 8, 2017
@frederoni frederoni self-assigned this Jan 8, 2017
Copy link
Contributor

@1ec5 1ec5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the comments below:

  • Remember to add a blurb about the scale bar to the iOS changelog and about the distance formatter to both changelogs.
  • MKMapView exposes a showsScale property that allows the developer to keep the scale visible at all times, even when the map is at rest. At a glance, it seems like that would be straightforward to implement in this PR. Ah, I see you’ve already noted that in the PR description.


#import "MGLScaleBarView.h"

@interface MGLScaleBarView (Private)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we fold this into MGLScaleBarView.h, which already has Project visibility?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like @friedbunny's suggestion of exposing some style properties. Perhaps alternating colors, border color etc and then we'll need this private header.

toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:5+self.contentInset.top]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we should explicitly constrain the scale bar and compass to each other and the scale bar and logo to each other, the way we currently constrain the logo and attribution button to each other?

Copy link
Contributor Author

@frederoni frederoni Jan 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any constraints between the logo and the attribution button.
The maximum width of the scale bar is screenWidth/2-padding which might be a bit too wide, especially on iPads but I don't think the answer is to constrain it to the compass. It makes positioning the components with contentInsets more prone to misplacement.

@@ -1223,6 +1258,12 @@ - (void)handlePanGesture:(UIPanGestureRecognizer *)pan
{
CGPoint offset = CGPointMake(velocity.x * self.decelerationRate / 4, velocity.y * self.decelerationRate / 4);
_mbglMap->moveBy({ offset.x, offset.y }, MGLDurationInSeconds(self.decelerationRate));
__weak MGLMapView *weakSelf = self;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we eliminate some of this repetitiveness by moving the -fadeOut call to the MapChangeRegionDidChangeAnimated handler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that first but then it'll fade out while you zoom or pan if you don't move consistently. :/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. In that case, perhaps -notifyGestureDidEndWithDrift: is what you want. If not, try factoring out the animation into a similar method.

#import "MGLScaleBarView_Private.h"

@interface MGLScaleBarView()
@property (nonatomic, assign, getter=isVisible) BOOL visible;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems redundant to UIView.hidden. Are the two orthogonal to each other somehow?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hidden would hide the view instantly so I use this property to flag the view as visible/invisible when fadeIn/fadeOut begins in order to prevent unwanted calls to those methods.

Copy link
Contributor

@1ec5 1ec5 Jan 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case, CALayer.hidden and CALayer.opacity are both animatable.


CGFloat barWidth = floorf(self.bounds.size.width / self.bars.count);

[self.bars enumerateObjectsUsingBlock:^(UIView * _Nonnull bar, NSUInteger idx, BOOL * _Nonnull stop) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you aren’t making use of functional programming, an ordinary for-in loop should be fine here.

@property (nonatomic) CALayer *borderLayer;
@end

static const CGFloat BAR_HEIGHT = 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use SCREAMING_SNAKE_CASE for macros and MGLUpperCamelCase for constants.

- (void)setRow:(NSArray<NSNumber *> *)row {
if (![row isEqualToArray:_row]) {
[_bars makeObjectsPerformSelector:@selector(removeFromSuperview)];
[_labels makeObjectsPerformSelector:@selector(removeFromSuperview)];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would setting self.subviews to the empty array also work here, or would that mess up constraints?

Copy link
Contributor Author

@frederoni frederoni Apr 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-[UIView subviews] is a readonly property

NSMutableArray *labels = [NSMutableArray array];
for (NSUInteger i = 0; i <= self.row.lastObject.integerValue; i++) {
UILabel *label = [[UILabel alloc] init];
label.text = @"0";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a placeholder string, or does it need to be localized?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this needs to be localized.

@1ec5 1ec5 added this to the ios-v3.5.0 milestone Jan 8, 2017
@1ec5 1ec5 added feature GL JS parity For feature parity with Mapbox GL JS labels Jan 8, 2017

_visible = NO;
_primaryColor = [UIColor colorWithRed:62.0/255.0 green:62.0/255.0 blue:62.0/255.0 alpha:1];
_secondaryColor = [UIColor colorWithRed:247.0/255.0 green:247.0/255.0 blue:247.0/255.0 alpha:1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The text and border colors should switch between white-on-black and black-on-white, depending on the background color of the current map style — e.g., the satellite and dark styles would need colors that are inverted from the current black-on-white.

Copy link
Contributor

@1ec5 1ec5 Jan 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will never be perfect, even if the developer gets full control over the scale bar’s colors. Consider Mapbox Satellite: a scale bar that’s readable over a lush forest may be unreadable over tundra and vice versa.

Apple Maps and Google Maps solve this problem by treating the scale bar’s labels just like any other labels on the base map: in Standard mode, the labels are set in black with a subtle, white stroke for contrast:

ios-standard
Apple Maps on iOS, Standard

macos-standard

Apple Maps on macOS, Standard

google-map
Google Maps on iOS, main map

google-terrain
Google Maps on iOS, Terrain

In Satellite mode, the labels are inverted to white with a subtle, black stroke. Another nice touch in Apple Maps is that the scale bar has slight translucency in Satellite mode to avoid becoming distracting.

ios-satellite
Apple Maps on iOS, Satellite

macos-satellite

Apple Maps on macOS, Satellite

google-satellite
Google Maps on iOS, Satellite

Our SDK has to cope with a wider variety of color schemes and challenges, since the style could contain anything. Here are a few possibilities:

  • Keep the appearance as-is. The scale bar isn’t the most important ornament on the screen; a little squinting may not be a showstopper.
  • Place a blurred background beneath the scale bar, as the macOS SDK does for attribution. Note that this effect would be similar but not identical to a visual effect view, whose effect is a bit too vibrant for a control that shouldn’t be conspicuous.
  • Choose between a light and dark appearance based on the style’s background color, as @friedbunny suggests.
  • Find the most similar symbol style layer and mimic its appearance. This could yield the best results – the highest fidelity to the style – but could also be somewhat unpredictable.

Whichever approach we take, I do think we should apply a stroke to the bar and labels at a minimum.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Find the most similar symbol style layer and mimic its appearance.

Or even a way for the developer to specify which symbol style layer they want the scale bar and logo view to match?

#import <UIKit/UIKit.h>

@interface MGLScaleBarView : UIView

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we expose any sort of styling properties publicly? Colors, typeface, position?

Copy link
Contributor

@1ec5 1ec5 Jan 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think knobs along these lines could be tail work. That way we can address customizability of the other ornaments at the same time in a consistent manner.

}

- (void)layoutBars {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: there’s an inconsistent line break here.

@@ -230,6 +231,8 @@ @interface MGLMapView () <UIGestureRecognizerDelegate,
@property (nonatomic) EAGLContext *context;
@property (nonatomic) GLKView *glView;
@property (nonatomic) UIImageView *glSnapshotView;
@property (nonatomic, readwrite) MGLScaleBarView *scaleBarView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We expose the other views that sit on top of the map (compass, logo, attribution) as public MGLMapView properties — I think it would be consistent and useful to do the same for this scale view. At minimum, it would allow a developer to hide the scale bar.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we expose the view as an ordinary UIView, the developer can still hide the scale bar and we retain more flexibility to iterate on the view’s design and structure.

@frederoni frederoni mentioned this pull request Jan 27, 2017
@1ec5
Copy link
Contributor

1ec5 commented Mar 4, 2017

Since this PR is scheduled for iOS SDK v3.5.0, it needs to be rebased and retargeted at the release-ios-v3.5.0-android-v5.0.0 branch.

@1ec5 1ec5 modified the milestones: ios-v3.5.0, ios-v3.6.0 Mar 9, 2017
@frederoni frederoni force-pushed the fred-distance-scale-bar branch 2 times, most recently from fca1f61 to e545cb5 Compare April 3, 2017 15:58
@1ec5
Copy link
Contributor

1ec5 commented Apr 4, 2017

I could see adding customization options causing this PR to drag on a bit longer, whereas the feature is already quite polished. How about we make MGLScaleBar private and change the public type of the scaleBar property to just UIView (so it can be hidden like the other ornaments)? Adding customization options can be a separate PR, once there's more clarity about the options people want.

@frederoni frederoni changed the title Distance formatter and scale bar [ios] Scale bar Apr 4, 2017
@frederoni
Copy link
Contributor Author

MGLScaleBarView is now private and supports imperial units. I had to change the roundingIncrement of MGLDistanceFormatter to avoid rounding less than 12.5 feet down to 0 and you can zoom into 2 feet per bar near the poles.

This PR is ready for another round 👀

toItem:self
attribute:NSLayoutAttributeTop
multiplier:1
constant:5+self.contentInset.top]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we stick to a more standard constant like 4 points?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've been using 5 on the compassView for quite a while. Let's revisit when we replace these constraints in #7716

}];
} else {
[self unrotateIfNeededForGesture];
[self notifyScaleBarGestureDidEnd];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the past, atomic gestures like double-tapping avoided calling -notifyGestureDidBegin and -notifyGestureDidEndWithDrift:. We should have these gestures call -notifyGestureDidBegin and -notifyGestureDidEndWithDrift: one right after the other, and merge -notifyScaleBarGestureDidEnd into -notifyGestureDidEndWithDrift:. That way there are fewer things to keep track of every time we finish a gesture.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this will also help with an issue I’m seeing in which pinching multiple times in quick succession causes the scale bar to stay visible; only pinching again gets the scale bar unstuck.

Copy link
Contributor Author

@frederoni frederoni Apr 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-[MGLMapView handlePanGesture:] calls -notifyGestureDidBegin.
We have to keep them separated if non-zoom-related gestures like panning shouldn't trigger the scale bar. Should we extract into -notifyGestureDidBegin and -notifyZoomChangingGestureDidBegin?
/cc @friedbunny

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@frederoni I think we have to keep the scale bar unhiding in -cameraIsChanging, otherwise programmatic zooming won’t trigger it. If that’s true, then bifurcating -notifyGestureDidBegin wouldn’t do us any good. (Have we considered programmatic zooming?)

If we don’t care about programmatic zoom triggering the scale bar, then perhaps we can keep a single method but have it take an enum, e.g., -notifyGestureDidBeginWithType: and MGLGestureType, that would define whether or not it was initiated by a zoom-related gesture. (Or just a -notifyGestureDidBeginWithZoom: boolean.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we considered programmatic zooming?

MapKit only shows the scale in response to user gestures, not in response to programmatic camera changes. However, there is an -[MKMapCamera showsScale] property that determines whether the scale bar is always visible: if the developer wants the scale bar to be visible during programmatic zooming, they can set and unset showsScale around that change to the map’s region or camera.



if (!self.scaleBarView.hidden) {
[(MGLScaleBarView *)self.scaleBarView setMetersPerPoint:[self metersPerPointAtLatitude:self.centerCoordinate.latitude]];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the scale bar is hidden while the user zooms the map, but then the developer unhides the scale bar afterwards? Would the scale bar remain accurate? Can we make it safe to call -[MGLScaleBarView setMetersPerPoint:metersPerPointAtLatitude:] even when MGLScaleBarView is hidden?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scale bar remains faded out until you set metersPerPoint making it safe. I'd prefer not to set metersPerPoint if the view is hidden to avoid excessive layout code from being executed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, something isn’t clicking for me: if the developer hides the scale bar using mapView.scaleView.hidden = YES, then the user zooms way in, then the developer sets mapView.scaleView.hidden = NO, wouldn’t the scale bar appear with the wrong scale until the user starts zooming again?

Copy link
Contributor Author

@frederoni frederoni Apr 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the zoom interaction occurred less than one second ago, it would show the incorrect scale for the remaining milliseconds up to 1 sec but since it was hidden, we never call -fadeIn leaving the view.alpha at 0 making the incorrect scale invisible. You have to set metersPerPoint again to make it visible and then it would show the correct scale.

However, it is possible to trigger the case you think of but it's slightly harder in practice;
Using scaleView.hidden = NO, zoom to fade in the scale bar, hide the scale bar, change the zoom, and unhide the scale bar all within 1 second in order for it to show an incorrect scale.

Though, we can remove the if-statement if the overhead is exaggerated.


@property (nonatomic, assign) CLLocationDistance metersPerPoint;

- (void)fadeOut;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this class is private, it would be good to give it some documentation.

map and fades out when the interaction stops. It’s positioned
in the upper-left corner.
*/
@property (nonatomic, readonly) UIView *scaleBarView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

“Scale bar view” is redundant. Let’s call it either a “scale bar” (scaleBar, MGLScaleBar) or a “scale view” (scaleView, MGLScaleView).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename to MGLScaleView, it aligns better with Cocoa naming conventions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what it’s worth, “bar” is primarily used in UITabBar.

Copy link
Contributor Author

@frederoni frederoni Apr 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

waiting with renaming the class to keep the reviewing process intact

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you've renamed the class to MGLScaleBar. Just to clarify, my comment above was meant to point out that UITabBar is a "bar" but almost nothing else is. Regardless, I'm comfortable with either name. 👍

A control indicating the scale of the map.

The scale bar becomes visible when a user interacts with the
map and fades out when the interaction stops. It’s positioned
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: wrap to 80 columns.

A control indicating the scale of the map.

The scale bar becomes visible when a user interacts with the
map and fades out when the interaction stops. It’s positioned
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: avoid contractions, which make the documentation sound too informal.

_row = @[@0, @0];

// @[meters, numberOfBars]
_metricTable = @[@[@1, @2],
Copy link
Contributor

@1ec5 1ec5 Apr 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be quite a bit of Objective-C overhead in managing this tabular data (in terms of syntax, not necessarily performance). These tables should be statically initialized as C arrays of anonymous structs. For example, you could declare an inline type:

static const struct {
    CLLocationDistance distance;
    NSUInteger numberOfBars;
} MGLNumberOfBarsByDistance[] = {
    { .distance = 1, .numberOfBars = 2 }, // or simply { 1, 2 }
    …
};

Then everything is fully typed, so you can iterate over the rules like this:

for (NSUInteger i = 0; i < sizeof(MGLNumberOfBarsByDistance) / sizeof(MGLNumberOfBarsByDistance[0]); i++ {
    //
    CLLocationDistance distance = MGLNumberOfBarsByDistance[i].distance;
    //
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that I'm adding more overhead when using static C arrays of anonymous structs, either in terms of manual memory management when allocating new C arrays or using a C++ list to return a subset of the rows needed for -[MGLScaleBarView validRows] and -[MGLScaleBarView preferredRowInRows:]. I'm leaning towards rewriting those methods in objc++.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two important points here:

  • The tables never change, so they should be allocated statically. A static C structure would be best; if an NSArray is really necessary, it should be created inside a dispatch_once block.
  • The table is already sorted by distance, so the valid rows are always contiguous. Therefore, we can represent the valid rows as a range of indices into the static table rather than allocating a new subarray each time we relayout.

This code doesn't benefit from NSArray's mutability or its ability to hold objects.

self.actualWidth,
MGLBarHeight+self.borderWidth*2);

self.containerView.layer.cornerRadius = 2.0f;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any objections to getting rid of the corner radius here? (The white border around the outside.)

screen shot 2017-04-05 at 12 11 52 am

It gives me a vague sense of unevenness, probably because the corners of the black outline are not rounded.

Copy link
Contributor Author

@frederoni frederoni Apr 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to agree. I wanted to round the background two pixels and the border one pixel but rounding one pixel renders differently in CG compared to Sketch.

UIColor *textColor = self.textColor;

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 1);
Copy link
Contributor

@friedbunny friedbunny Apr 5, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stroke width here (around the outside of the label’s numbers/text) feels a bit too thin and diminishes legibility.

stroke-light
dark-stroke
Top: 1 unit; bottom: 2 units

It does look like widening the stroke width causes the left/right outside edges to get cropped a bit, though... especially the zero character — its stroke is very uneven and sharp when 2.

@friedbunny
Copy link
Contributor

The scale bar, as of 7de5c27:

2017-04-04 23_19_11
Apologies for the choppy gif — bar changes are smooooth.

@1ec5 1ec5 mentioned this pull request Apr 5, 2017
@frederoni frederoni force-pushed the fred-distance-scale-bar branch 2 times, most recently from 08a7733 to 9a7bfd2 Compare April 7, 2017 08:38
};

static const struct {
struct MGLRow row;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one extra level of indirection. All we need is an array of MGLRows; this creates an array of anonymous structs containing MGLRows. With a simple array of MGLRows, we can eliminate some of the braces below.

My earlier suggestion was that, as long as you don't need to refer to the specific type of these rows anywhere else, it's possible to inline MGLRow here, without naming it, and use auto everywhere else you'd refer to the row's type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyhow, since the Imperial table needs access to the same type as this table, it does make sense to name MGLRow, just not to then stuff it into an anonymous struct as this code does.

@frederoni frederoni force-pushed the fred-distance-scale-bar branch 3 times, most recently from 180f0ad to 94fe3ac Compare April 10, 2017 16:20
@1ec5
Copy link
Contributor

1ec5 commented Apr 12, 2017

A couple more observations about MapKit’s scale bar implementation:

  • MapKit hides the scale bar as soon as it needs to display a distance longer than 375 miles or 750 kilometers. (This distance is dependent on both the altitude and latitude, so not just the zoom level.)
  • When the showsScale property is set to YES, the scale bar is always visible. When it’s set to the default of NO, the scale is never visible. The auto-fading functionality appears to be specific to the Maps application on iOS. I like the auto-fading functionality, but I suppose it would simplify the code somewhat to unconditionally show or hide the scale bar. 🤷‍♂️

@frederoni
Copy link
Contributor Author

frederoni commented Apr 12, 2017

Leave show/hide up to the developer simplifies a lot indeed. 👍
I added a maximum scale of 400 miles or 800 kilometers. I also removed the fade in/out animation.

? MGLMetricTable[count-1].distance
: MGLImperialTable[count-1].distance;

self.alpha = maximumDistance > allowedDistance ? 0 : 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MapKit fades the scale bar in and out as it appears and disappears due to the maximum distance threshold. We could use a UIView animation block here perhaps.

@@ -226,6 +226,12 @@ IB_DESIGNABLE
- (IBAction)reloadStyle:(id)sender;

/**
A control indicating the scale of the map. The scale bar is positioned in the
upper-left corner.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the view is hidden by default.

CGFloat alpha = maximumDistance > allowedDistance ? .0f : 1.0f;

if(self.alpha != alpha) {
[UIView animateWithDuration:.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, most of MGLMapView’s animations occur within 300 milliseconds, via MGLAnimationDuration. (200 milliseconds is fine, though.)

@frederoni frederoni merged commit 8eb23cb into master Apr 16, 2017
@frederoni frederoni deleted the fred-distance-scale-bar branch April 16, 2017 15:24
@1ec5 1ec5 removed the macOS Mapbox Maps SDK for macOS label Jun 23, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feature GL JS parity For feature parity with Mapbox GL JS iOS Mapbox Maps SDK for iOS MapKit parity For feature parity with MapKit on iOS or macOS
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants