summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gyp/platform-ios.gypi2
-rw-r--r--include/mbgl/ios/MGLMapView.h11
-rw-r--r--platform/ios/MGLMapView.mm175
-rw-r--r--platform/ios/MGLMapboxEvents.m24
-rw-r--r--platform/ios/NSProcessInfo+MGLAdditions.h7
-rw-r--r--platform/ios/NSProcessInfo+MGLAdditions.m10
6 files changed, 199 insertions, 30 deletions
diff --git a/gyp/platform-ios.gypi b/gyp/platform-ios.gypi
index fc6771d83a..998a0d1b8f 100644
--- a/gyp/platform-ios.gypi
+++ b/gyp/platform-ios.gypi
@@ -30,6 +30,8 @@
'../include/mbgl/ios/MGLMetricsLocationManager.h',
'../platform/ios/MGLMetricsLocationManager.m',
'../include/mbgl/ios/MGLTypes.h',
+ '../platform/ios/NSProcessInfo+MGLAdditions.h',
+ '../platform/ios/NSProcessInfo+MGLAdditions.m',
'../platform/ios/NSString+MGLAdditions.h',
'../platform/ios/NSString+MGLAdditions.m',
'../platform/ios/vendor/SMCalloutView/SMCalloutView.h',
diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h
index dcf1313a8c..4139ef51cc 100644
--- a/include/mbgl/ios/MGLMapView.h
+++ b/include/mbgl/ios/MGLMapView.h
@@ -13,20 +13,21 @@
* Use of MGLMapView requires a Mapbox API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/). If you instantiate an MGLMapView from Interface Builder, rendering of the map won't begin until the accessToken property has been set.
*
* @warning Please note that you are responsible for getting permission to use the map data, and for ensuring your use adheres to the relevant terms of use. */
+IB_DESIGNABLE
@interface MGLMapView : UIView
#pragma mark - Initializing a Map View
/** @name Initializing a Map View */
-/** Initialize a map view with a given frame, style URL, and access token.
+/** Initialize a map view with a given frame, access token, and style URL.
* @param frame The frame with which to initialize the map view.
* @param accessToken A Mapbox API access token.
* @param styleURL The map style URL to use. Can be either an HTTP/HTTPS URL or a Mapbox map ID style URL (`mapbox://<user.style>`).
* @return An initialized map view, or `nil` if the map view was unable to be initialized. */
- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL;
-/** Initialize a map view with a given frame, the default style, and an access token.
+/** Initialize a map view with the default style given a frame and access token.
* @param frame The frame with which to initialize the map view.
* @param accessToken A Mapbox API access token.
* @return An initialized map view, or `nil` if the map view was unable to be initialized. */
@@ -49,7 +50,7 @@
/** A view controller whose top and bottom layout guides to use for proper setup of constraints in the map view internals.
*
* Certain components of the map view, such as the heading compass and the data attribution button, need to be aware of the view controller layout in order to avoid positioning content under a top navigation bar or a bottom toolbar. */
-@property (nonatomic, weak) UIViewController *viewControllerForLayoutGuides;
+@property (nonatomic, weak) IBOutlet UIViewController *viewControllerForLayoutGuides;
#pragma mark - Accessing Map Properties
@@ -81,7 +82,7 @@
/** @name Accessing the Delegate */
// TODO
-@property(nonatomic, weak) id<MGLMapViewDelegate> delegate;
+@property(nonatomic, weak) IBOutlet id<MGLMapViewDelegate> delegate;
#pragma mark - Manipulating the Visible Portion of the Map
@@ -134,7 +135,7 @@
- (void)setDirection:(CLLocationDirection)direction animated:(BOOL)animated;
/** Resets the map rotation to a northern heading. */
-- (void)resetNorth;
+- (IBAction)resetNorth;
#pragma mark - Converting Map Coordinates
diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm
index 67a62680e8..b1a2eeadbb 100644
--- a/platform/ios/MGLMapView.mm
+++ b/platform/ios/MGLMapView.mm
@@ -16,6 +16,7 @@
#import "MGLTypes.h"
#import "NSString+MGLAdditions.h"
+#import "NSProcessInfo+MGLAdditions.h"
#import "MGLAnnotation.h"
#import "MGLUserLocationAnnotationView.h"
#import "MGLUserLocation_Private.h"
@@ -46,6 +47,7 @@ static dispatch_once_t loadGLExtensions;
NSString *const MGLDefaultStyleName = @"Emerald";
NSString *const MGLStyleVersion = @"7";
NSString *const MGLDefaultStyleMarkerSymbolName = @"default_marker";
+NSString *const MGLMapboxAccessTokenManagerURLDisplayString = @"mapbox.com/account/apps";
const NSTimeInterval MGLAnimationDuration = 0.3;
const CGSize MGLAnnotationUpdateViewportOutset = {150, 150};
@@ -88,7 +90,9 @@ static NSURL *MGLURLForBundledStyleNamed(NSString *styleName)
@end
-@implementation MGLMapView
+@implementation MGLMapView {
+ BOOL _isTargetingInterfaceBuilder;
+}
#pragma mark - Setup & Teardown -
@@ -106,24 +110,22 @@ MBGLView *mbglView = nullptr;
mbgl::SQLiteCache *mbglFileCache = nullptr;
mbgl::DefaultFileSource *mbglFileSource = nullptr;
-- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken
+- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self && [self commonInit])
{
- [self setAccessToken:accessToken];
-
- if (accessToken)
- {
- // If style is set directly, pass it on. If not, if we have an access
- // token, we can pass nil and use the default style.
- //
- self.styleURL = nil;
- }
+ self.styleURL = nil;
+ return self;
}
- return self;
+ return nil;
+}
+
+- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken
+{
+ return [self initWithFrame:frame accessToken:accessToken styleURL:nil];
}
- (instancetype)initWithFrame:(CGRect)frame accessToken:(NSString *)accessToken styleURL:(NSURL *)styleURL
@@ -175,6 +177,11 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
- (void)setStyleURL:(NSURL *)styleURL
{
+ if ( _isTargetingInterfaceBuilder )
+ {
+ return;
+ }
+
if ( ! styleURL)
{
styleURL = MGLURLForBundledStyleNamed([NSString stringWithFormat:@"%@-v%@",
@@ -193,6 +200,8 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
- (BOOL)commonInit
{
+ _isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent;
+
// create context
//
_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
@@ -362,8 +371,11 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
_regionChangeDelegateQueue = [NSOperationQueue new];
_regionChangeDelegateQueue.maxConcurrentOperationCount = 1;
- // start the main loop
- mbglMap->start();
+ // start the main loop, but not on the IB canvas
+ if ( ! _isTargetingInterfaceBuilder)
+ {
+ mbglMap->start();
+ }
// metrics: map load event
const mbgl::LatLng latLng = mbglMap->getLatLng();
@@ -550,7 +562,11 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr;
- (void)layoutSubviews
{
[super layoutSubviews];
- mbglMap->triggerUpdate();
+
+ if ( ! _isTargetingInterfaceBuilder)
+ {
+ mbglMap->triggerUpdate();
+ }
}
#pragma mark - Life Cycle -
@@ -2186,6 +2202,135 @@ CLLocationCoordinate2D latLngToCoordinate(mbgl::LatLng latLng)
[self notifyMapChange:@(mbgl::MapChangeRegionIsChanging)];
}
+- (void)prepareForInterfaceBuilder
+{
+ [super prepareForInterfaceBuilder];
+
+ self.layer.borderColor = [UIColor colorWithWhite:184/255. alpha:1].CGColor;
+ self.layer.borderWidth = 1;
+
+ if (self.accessToken)
+ {
+ self.layer.backgroundColor = [UIColor colorWithRed:59/255.
+ green:178/255.
+ blue:208/255.
+ alpha:0.8].CGColor;
+
+ UIImage *image = [[self class] resourceImageNamed:@"mapbox.png"];
+ UIImageView *previewView = [[UIImageView alloc] initWithImage:image];
+ previewView.translatesAutoresizingMaskIntoConstraints = NO;
+ [self addSubview:previewView];
+ [self addConstraint:
+ [NSLayoutConstraint constraintWithItem:previewView
+ attribute:NSLayoutAttributeCenterXWithinMargins
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeCenterXWithinMargins
+ multiplier:1
+ constant:0]];
+ [self addConstraint:
+ [NSLayoutConstraint constraintWithItem:previewView
+ attribute:NSLayoutAttributeCenterYWithinMargins
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeCenterYWithinMargins
+ multiplier:1
+ constant:0]];
+ }
+ else
+ {
+ UIView *diagnosticView = [[UIView alloc] init];
+ diagnosticView.translatesAutoresizingMaskIntoConstraints = NO;
+ [self addSubview:diagnosticView];
+
+ // Headline
+ UILabel *headlineLabel = [[UILabel alloc] init];
+ headlineLabel.text = @"No Access Token";
+ headlineLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];
+ headlineLabel.textAlignment = NSTextAlignmentCenter;
+ headlineLabel.numberOfLines = 1;
+ headlineLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [headlineLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
+ forAxis:UILayoutConstraintAxisHorizontal];
+ [diagnosticView addSubview:headlineLabel];
+
+ // Explanation
+ UILabel *explanationLabel = [[UILabel alloc] init];
+ explanationLabel.text = @"To display a map here, you must provide a Mapbox access token. Get an access token from:";
+ explanationLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+ explanationLabel.numberOfLines = 0;
+ explanationLabel.translatesAutoresizingMaskIntoConstraints = NO;
+ [explanationLabel setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
+ forAxis:UILayoutConstraintAxisHorizontal];
+ [diagnosticView addSubview:explanationLabel];
+
+ // Link
+ UIButton *linkButton = [UIButton buttonWithType:UIButtonTypeSystem];
+ [linkButton setTitle:MGLMapboxAccessTokenManagerURLDisplayString forState:UIControlStateNormal];
+ linkButton.translatesAutoresizingMaskIntoConstraints = NO;
+ [linkButton setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
+ forAxis:UILayoutConstraintAxisHorizontal];
+ [diagnosticView addSubview:linkButton];
+
+ // More explanation
+ UILabel *explanationLabel2 = [[UILabel alloc] init];
+ explanationLabel2.text = @"and enter it into the Access Token field in the Attributes inspector.";
+ explanationLabel2.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
+ explanationLabel2.numberOfLines = 0;
+ explanationLabel2.translatesAutoresizingMaskIntoConstraints = NO;
+ [explanationLabel2 setContentCompressionResistancePriority:UILayoutPriorityDefaultLow
+ forAxis:UILayoutConstraintAxisHorizontal];
+ [diagnosticView addSubview:explanationLabel2];
+
+ // Constraints
+ NSDictionary *views = @{
+ @"container": diagnosticView,
+ @"headline": headlineLabel,
+ @"explanation": explanationLabel,
+ @"link": linkButton,
+ @"explanation2": explanationLabel2,
+ };
+ [self addConstraint:
+ [NSLayoutConstraint constraintWithItem:diagnosticView
+ attribute:NSLayoutAttributeCenterYWithinMargins
+ relatedBy:NSLayoutRelationEqual
+ toItem:self
+ attribute:NSLayoutAttributeCenterYWithinMargins
+ multiplier:1
+ constant:0]];
+ [self addConstraints:
+ [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[container(20@20)]-|"
+ options:NSLayoutFormatAlignAllCenterY
+ metrics:nil
+ views:views]];
+ [self addConstraints:
+ [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[headline]-[explanation]-[link]-[explanation2]|"
+ options:0
+ metrics:nil
+ views:views]];
+ [self addConstraints:
+ [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[headline]|"
+ options:0
+ metrics:nil
+ views:views]];
+ [self addConstraints:
+ [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[explanation]|"
+ options:0
+ metrics:nil
+ views:views]];
+ [self addConstraints:
+ [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[link]|"
+ options:0
+ metrics:nil
+ views:views]];
+ [self addConstraints:
+ [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[explanation2]|"
+ options:0
+ metrics:nil
+ views:views]];
+ }
+}
+
class MBGLView : public mbgl::View
{
public:
diff --git a/platform/ios/MGLMapboxEvents.m b/platform/ios/MGLMapboxEvents.m
index 1db0f9e9f6..d21a723d94 100644
--- a/platform/ios/MGLMapboxEvents.m
+++ b/platform/ios/MGLMapboxEvents.m
@@ -6,6 +6,7 @@
#import <CoreTelephony/CTCarrier.h>
#import "MGLMetricsLocationManager.h"
+#import "NSProcessInfo+MGLAdditions.h"
#include <sys/sysctl.h>
@@ -176,17 +177,20 @@ NSString *const MGLEventGestureRotateStart = @"Rotation";
static dispatch_once_t onceToken;
static MGLMapboxEvents *_sharedManager;
dispatch_once(&onceToken, ^{
- void (^setupBlock)() = ^{
- _sharedManager = [[self alloc] init];
- // setup dedicated location manager on first use
- [MGLMetricsLocationManager sharedManager];
- };
- if ( ! [[NSThread currentThread] isMainThread]) {
- dispatch_sync(dispatch_get_main_queue(), ^{
+ if ( ! NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent) {
+ void (^setupBlock)() = ^{
+ _sharedManager = [[self alloc] init];
+ // setup dedicated location manager on first use
+ [MGLMetricsLocationManager sharedManager];
+ };
+ if ( ! [[NSThread currentThread] isMainThread]) {
+ dispatch_sync(dispatch_get_main_queue(), ^{
+ setupBlock();
+ });
+ }
+ else {
setupBlock();
- });
- } else {
- setupBlock();
+ }
}
});
return _sharedManager;
diff --git a/platform/ios/NSProcessInfo+MGLAdditions.h b/platform/ios/NSProcessInfo+MGLAdditions.h
new file mode 100644
index 0000000000..a117f3b76d
--- /dev/null
+++ b/platform/ios/NSProcessInfo+MGLAdditions.h
@@ -0,0 +1,7 @@
+#import <Foundation/Foundation.h>
+
+@interface NSProcessInfo (MGLAdditions)
+
+- (BOOL)mgl_isInterfaceBuilderDesignablesAgent;
+
+@end
diff --git a/platform/ios/NSProcessInfo+MGLAdditions.m b/platform/ios/NSProcessInfo+MGLAdditions.m
new file mode 100644
index 0000000000..fca183c1f7
--- /dev/null
+++ b/platform/ios/NSProcessInfo+MGLAdditions.m
@@ -0,0 +1,10 @@
+#import "NSProcessInfo+MGLAdditions.h"
+
+@implementation NSProcessInfo (MGLAdditions)
+
+- (BOOL)mgl_isInterfaceBuilderDesignablesAgent
+{
+ return [self.processName isEqualToString:@"IBDesignablesAgentCocoaTouch"];
+}
+
+@end