-
Notifications
You must be signed in to change notification settings - Fork 35
Add change worldview boundaries example #382
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
#import "ChangeWorldviewBoundaries.h" | ||
|
||
@import Mapbox; | ||
|
||
NSString *const MBXExampleChangeWorldviewBoundaries = @"ChangeWorldviewBoundariesExample"; | ||
|
||
@interface ChangeWorldviewBoundariesExample () | ||
|
||
@property (nonatomic) MGLMapView *mapView; | ||
@property MGLLineStyleLayer *layer; | ||
|
||
|
||
@end | ||
|
||
@implementation ChangeWorldviewBoundariesExample | ||
|
||
- (void)viewDidLoad { | ||
[super viewDidLoad]; | ||
|
||
self.mapView = [[MGLMapView alloc] initWithFrame: CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)]; | ||
self.mapView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | ||
|
||
// Set the map's initial style, center coordinate, and zoom level | ||
self.mapView.styleURL = [MGLStyle lightStyleURL]; | ||
[self.mapView setCenterCoordinate:CLLocationCoordinate2DMake(25.251, 95.69) | ||
zoomLevel:3 | ||
animated:NO]; | ||
[self.view addSubview:self.mapView]; | ||
|
||
// Create a UISegmentedControl to toggle between map styles | ||
UISegmentedControl *styleToggle =[[UISegmentedControl alloc] initWithItems:@[@" US ", @" CN ", @" IN ", @" All "]]; | ||
styleToggle.translatesAutoresizingMaskIntoConstraints = NO; | ||
styleToggle.tintColor = [UIColor colorWithRed:0.976f green:0.843f blue:0.831f alpha:1]; | ||
styleToggle.backgroundColor = [UIColor colorWithRed:0.721f green:0.804f blue:0.831f alpha:1]; | ||
styleToggle.layer.cornerRadius = 4; | ||
styleToggle.clipsToBounds = YES; | ||
[self.view insertSubview:styleToggle aboveSubview:self.mapView]; | ||
[styleToggle addTarget:self action:@selector(changeStyle:) forControlEvents:UIControlEventValueChanged]; | ||
|
||
// Configure autolayout constraints for the UISegmentedControl to align | ||
// at the bottom of the map view and above the Mapbox logo and attribution | ||
NSMutableArray *constraints = [NSMutableArray array]; | ||
|
||
[constraints addObject:[NSLayoutConstraint constraintWithItem:styleToggle attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.mapView attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:1.0]]; | ||
[constraints addObject:[NSLayoutConstraint constraintWithItem:styleToggle attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.mapView.logoView attribute:NSLayoutAttributeTop multiplier:1 constant:-20]]; | ||
|
||
[self.view addConstraints:constraints]; | ||
} | ||
|
||
// Change the map style based on the selected index of the UISegmentedControl | ||
- (void)changeStyle:(UISegmentedControl *)sender { | ||
|
||
MGLStyle *style = self.mapView.style; | ||
|
||
MGLVectorTileSource *source = [[MGLVectorTileSource alloc] initWithIdentifier:@"admin-bounds" configurationURL: [NSURL URLWithString:@"mapbox://mapbox.mapbox-streets-v8"]]; | ||
|
||
if ([_layer.identifier isEqual: @"admin"]) { | ||
printf("source already exists"); | ||
[style removeLayer:_layer]; | ||
|
||
} else { | ||
_layer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"admin" source:source]; | ||
[style addSource:source]; | ||
} | ||
_layer.sourceLayerIdentifier = @"admin"; | ||
_layer.lineColor = [NSExpression expressionForConstantValue: UIColor.lightGrayColor]; | ||
|
||
switch(sender.selectedSegmentIndex){ | ||
case 0: | ||
printf("US"); | ||
_layer.predicate = [ NSPredicate predicateWithFormat: @"CAST(worldview, 'NSString') == 'US'"]; | ||
[style addLayer:_layer]; | ||
break; | ||
case 1: | ||
printf("CN"); | ||
_layer.predicate = [ NSPredicate predicateWithFormat: @"CAST(worldview, 'NSString') == 'CN'"]; | ||
[style addLayer:_layer]; | ||
break; | ||
case 2: | ||
printf("IN"); | ||
_layer.predicate = [ NSPredicate predicateWithFormat: @"CAST(worldview, 'NSString') == 'IN'"]; | ||
[style addLayer:_layer]; | ||
break; | ||
case 3: | ||
printf("All"); | ||
_layer.predicate = [ NSPredicate predicateWithFormat: @"CAST(worldview, 'NSString') == 'all'"]; | ||
[style addLayer:_layer]; | ||
break; | ||
default: | ||
[style addLayer:_layer]; | ||
break; | ||
} | ||
} | ||
|
||
@end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// ChangeWorldviewBoundaries.h | ||
// Examples | ||
// | ||
// Created by ZiZi Miles on 12/11/19. | ||
// Copyright © 2019 Mapbox. All rights reserved. | ||
// | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. By default we remove these comments for new files. |
||
#import <UIKit/UIKit.h> | ||
|
||
@interface ChangeWorldviewBoundariesExample : UIViewController | ||
|
||
@end | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import UIKit | ||
import Mapbox | ||
|
||
@objc(ChangeWorldviewBoundariesExample_Swift) | ||
|
||
class ChangeWorldviewBoundariesExample: UIViewController, MGLMapViewDelegate { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The view controller is conforming to the |
||
|
||
let mapView = MGLMapView() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can take care of the map view's initialization and style setting in one shot with this initializer: MGLMapView(frame: CGRect, styleURL: MGLStyleURL) I recommend doing this in |
||
let source = MGLVectorTileSource(identifier: "admin-bounds", configurationURL: NSURL(string: "mapbox://mapbox.mapbox-streets-v8")! as URL) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this source is already included in Mapbox Light by default, you can access it instead with |
||
var adminLayers = [String]() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
var layer: MGLLineStyleLayer? | ||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
|
||
mapView.frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can assign this to |
||
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight] | ||
|
||
// Set the map's initial style, center coordinate, and zoom level | ||
mapView.styleURL = MGLStyle.lightStyleURL | ||
mapView.setCenter(CLLocationCoordinate2D(latitude: 25.251, longitude: 95.69), zoomLevel: 3, animated: false) | ||
|
||
view.addSubview(mapView) | ||
|
||
// Create a UISegmentedControl to toggle between map styles | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The style itself isn't changing, we're just toggling source visibility. |
||
let styleToggle = UISegmentedControl(items: [" US ", " CN ", " IN "," All "]) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because we're not actually changing the style, you may want to consider renaming this to |
||
styleToggle.translatesAutoresizingMaskIntoConstraints = false | ||
styleToggle.tintColor = UIColor(red: 0.976, green: 0.843, blue: 0.831, alpha: 1) | ||
styleToggle.backgroundColor = UIColor(red: 184/255, green: 205/255, blue: 212/255, alpha: 1) | ||
styleToggle.layer.cornerRadius = 4 | ||
styleToggle.clipsToBounds = true | ||
// styleToggle.selectedSegmentIndex = 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you want to uncomment this? |
||
view.insertSubview(styleToggle, aboveSubview: mapView) | ||
styleToggle.addTarget(self, action: #selector(changeStyle(sender:)), for: .valueChanged) | ||
|
||
// Configure autolayout constraints for the UISegmentedControl to align | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
// at the bottom of the map view and above the Mapbox logo and attribution | ||
NSLayoutConstraint.activate([NSLayoutConstraint(item: styleToggle, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: mapView, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0.0)]) | ||
NSLayoutConstraint.activate([NSLayoutConstraint(item: styleToggle, attribute: .bottom, relatedBy: .equal, toItem: mapView.logoView, attribute: .top, multiplier: 1, constant: -20)]) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An easier (and less lengthy) way to write constraints is to use the Before: NSLayoutConstraint(item: styleToggle, attribute: NSLayoutConstraint.Attribute.centerX, relatedBy: NSLayoutConstraint.Relation.equal, toItem: mapView, attribute: NSLayoutConstraint.Attribute.centerX, multiplier: 1.0, constant: 0.0) After, using styleToggle.centerX.constraint(equalTo: mapView.centerX) I recommend having a look at this blog post for more context! You can also put all of your constraints into one |
||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To keep |
||
|
||
// Change the map style based on the selected index of the UISegmentedControl | ||
@objc func changeStyle(sender: UISegmentedControl) { | ||
|
||
guard let style = self.mapView.style else {return} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
However, I think you could refactor this to not require accessing |
||
|
||
if layer?.identifier == "admin" { | ||
print("source already exists") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't forget to remove this :) |
||
style.removeLayer(layer!) | ||
} else { | ||
layer = MGLLineStyleLayer(identifier: "admin", source: source) | ||
style.addSource(source) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. layer = MGLLineStyleLayer(identifier: "admin", source: source)
style.addSource(source) This only happens the first time a user selects a segment. I don't think this code is necessary, since it appears that Mapbox Light already includes admin boundary style layers. That layer just needs to be accessed with |
||
layer?.sourceLayerIdentifier = "admin" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The layer identifier has already been defined in |
||
layer?.lineColor = NSExpression(forConstantValue: UIColor.lightGray) | ||
|
||
switch sender.selectedSegmentIndex { | ||
case 0: | ||
|
||
layer?.predicate = NSPredicate(format: "CAST(worldview, 'NSString') == 'US'") | ||
style.addLayer(layer!) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once you refactor this to use the built-in admin layer, you can remove all instances of |
||
case 1: | ||
layer?.predicate = NSPredicate(format: "CAST(worldview, 'NSString') == 'CN'") | ||
style.addLayer(layer!) | ||
case 2: | ||
layer?.predicate = NSPredicate(format: "CAST(worldview, 'NSString') == 'IN'") | ||
style.addLayer(layer!) | ||
case 3: | ||
layer?.predicate = NSPredicate(format: "CAST(worldview, 'NSString') == 'all'") | ||
style.addLayer(layer!) | ||
default: | ||
style.addLayer(layer!) | ||
|
||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.