This updates the package script to include a pre-built iOS app in the published assets of the dynamic SDK. It symlinks the Mapbox.framework in that dynamic build to the demo app so the only real increase in size is the demo Xcode project itself. The addtional step in the publish script checks that the Mapbox.framework that is symlinked in for building in the demo project can actually be built. If it cannot, then the step is skipped and the build will continue as it normally would. Since the demo app is currently not required for publishing it should not block publishing a build.
240 lines
9.9 KiB
Swift
240 lines
9.9 KiB
Swift
import UIKit
|
|
import Mapbox
|
|
|
|
/*
|
|
A simple example that uses the Mapbox Outdoors style to view
|
|
Yosemite National Park, USA with a polygon visualization of the
|
|
park boundary that can be interacted with.
|
|
|
|
A demo access token has been provided for convenience and it may
|
|
stop working in the future.
|
|
|
|
You can obtain your own access token from the
|
|
[Mapbox account page](https://www.mapbox.com/studio/account/tokens/)
|
|
and add it to this application's Info.plist as the value for
|
|
MGLMapboxAccessToken
|
|
*/
|
|
class ViewController: UIViewController {
|
|
|
|
@IBOutlet weak var mapViewContainer: UIView!
|
|
@IBOutlet weak var annotationContextView: UIView!
|
|
@IBOutlet weak var accessTokenWarningView: UIView!
|
|
|
|
var mapView: MGLMapView!
|
|
|
|
// Define a name for our annotation
|
|
let annotationIdentifier = "yosemite-fill-layer"
|
|
|
|
// Define the name of the map label layer we will want our annotation to be placed under
|
|
let styleLabelLayer = "mountain-peak-label"
|
|
|
|
// The initial center geometric coordinate for the map to display - this is Yosemite National Park, USA
|
|
let centerCoordinate = CLLocationCoordinate2DMake(37.742241, -119.576923)
|
|
|
|
// MARK: - View controller life cycle
|
|
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
|
|
setupAnnotationContextView()
|
|
setupAndAddMapView()
|
|
setupGestureHandling()
|
|
}
|
|
|
|
// MARK: - Map object interaction
|
|
|
|
@objc func didTapMap(sender: UITapGestureRecognizer) {
|
|
|
|
// Search for annotation at tap point
|
|
// If the annotation is found at the tap point then modify some of its properties
|
|
// If the annotation is not found at the tap point, reset the annotation back to the way it was when originally added
|
|
if let layer = mapView.style?.layer(withIdentifier: annotationIdentifier) as? MGLFillExtrusionStyleLayer {
|
|
let point = sender.location(in: mapView)
|
|
let features = mapView.visibleFeatures(at: point, styleLayerIdentifiers: [annotationIdentifier])
|
|
if features.count > 0 {
|
|
layer.fillExtrusionOpacity = MGLStyleValue(rawValue: 0.9)
|
|
layer.fillExtrusionHeight = MGLStyleValue(rawValue: 5000)
|
|
let camera = MGLMapCamera(lookingAtCenter: centerCoordinate, fromDistance: 100000, pitch: 60, heading: 180)
|
|
mapView.fly(to: camera, withDuration: 8, completionHandler: nil)
|
|
annotationContextView.alpha = 1.0
|
|
} else {
|
|
layer.fillExtrusionOpacity = MGLStyleValue(rawValue: 0.5)
|
|
layer.fillExtrusionHeight = MGLStyleValue(rawValue: 0)
|
|
let camera = MGLMapCamera(lookingAtCenter: centerCoordinate, fromDistance: 100000, pitch: 60, heading: 0)
|
|
mapView.fly(to: camera, withDuration: 1, completionHandler: nil)
|
|
annotationContextView.alpha = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Initialization and setup
|
|
|
|
/*
|
|
Simple (but somewhat styled) stub of a view to present
|
|
contextual information about tapped objects on the map.
|
|
*/
|
|
fileprivate func setupAnnotationContextView() {
|
|
annotationContextView.alpha = 0
|
|
let blurView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
|
blurView.frame = annotationContextView.bounds
|
|
blurView.layer.cornerRadius = 5
|
|
blurView.clipsToBounds = true
|
|
blurView.translatesAutoresizingMaskIntoConstraints = false
|
|
annotationContextView.insertSubview(blurView, at: 0)
|
|
blurView.topAnchor.constraint(equalTo: annotationContextView.topAnchor).isActive = true
|
|
blurView.leftAnchor.constraint(equalTo: annotationContextView.leftAnchor).isActive = true
|
|
blurView.rightAnchor.constraint(equalTo: annotationContextView.rightAnchor).isActive = true
|
|
blurView.bottomAnchor.constraint(equalTo: annotationContextView.bottomAnchor).isActive = true
|
|
}
|
|
|
|
/*
|
|
Create and add a Mapbox map view to the the view
|
|
intended to contain it. Setup with the style, initial
|
|
location in the world, and make this object the delegate
|
|
of the map. Finally, set up a camera to control how the
|
|
user will view the map initially.
|
|
*/
|
|
fileprivate func setupAndAddMapView() {
|
|
mapView = MGLMapView(frame: mapViewContainer.bounds)
|
|
mapView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
|
|
mapView.styleURL = MGLStyle.outdoorsStyleURL(withVersion: 10)
|
|
mapView.setCenter(centerCoordinate, zoomLevel: 10, animated: false)
|
|
mapView.delegate = self
|
|
mapViewContainer.addSubview(mapView)
|
|
|
|
accessTokenWarningView.layer.cornerRadius = 5
|
|
accessTokenWarningView.isHidden = true
|
|
|
|
// This demo access token has been provided for convenience and it may
|
|
// stop working in the future.
|
|
// You can obtain your own access token from the
|
|
// [Mapbox account page](https://www.mapbox.com/studio/account/tokens/)
|
|
// and add it to this application's Info.plist as the value for MGLMapboxAccessToken
|
|
if MGLAccountManager.accessToken() == "pk.eyJ1IjoibWFwYm94IiwiYSI6ImNqYThuNnZ3NTA5MGMyd3F1cmF1eW1xaGEifQ.TdBTSHHPeT1pfLZ_6x_1vA" {
|
|
accessTokenWarningView.isHidden = false
|
|
}
|
|
|
|
let camera = MGLMapCamera(lookingAtCenter: centerCoordinate, fromDistance: 100000, pitch: 60, heading: 0)
|
|
mapView.setCamera(camera, animated: false)
|
|
}
|
|
|
|
/*
|
|
Add a gesture recognizer that will be used to handle user
|
|
interactions with the map.
|
|
*/
|
|
fileprivate func setupGestureHandling() {
|
|
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTapMap))
|
|
mapView.addGestureRecognizer(tapGestureRecognizer)
|
|
}
|
|
}
|
|
|
|
/*
|
|
Implementation of Mapbox map view delegate methods relevant to this application
|
|
*/
|
|
extension ViewController: MGLMapViewDelegate {
|
|
|
|
/*
|
|
When the map has finished loading the style it's a great time
|
|
to do work like adding annotations.
|
|
*/
|
|
func mapView(_ mapView: MGLMapView, didFinishLoading style: MGLStyle) {
|
|
// This project's bundle contains a geojson file that represents the park boundary of Yosemite National Park in the USA
|
|
let url = URL(fileURLWithPath: Bundle.main.path(forResource: "yose", ofType: "geojson")!)
|
|
|
|
// Create an instance of a structure to represent a polygon
|
|
// fill visualization that can be injeced into the map's style layers
|
|
var annotation = StyledAnnotation(identifier: annotationIdentifier, resource: url, type: .extrusion)
|
|
annotation.color = UIColor(red:1.00, green:0.95, blue:0.75, alpha:1.0)
|
|
annotation.opacity = 0.75
|
|
annotation.transitionDuration = 0.35
|
|
|
|
// Inject the annotation below the label layer so some map labels
|
|
// are still visible
|
|
mapView.addStyledAnnotation(annotation, belowLayer: styleLabelLayer)
|
|
|
|
// Alternatively, a more traditional annotation / marker API
|
|
let pointFeatureAnnotation = MGLPointFeature()
|
|
let offsetCoordinate = CLLocationCoordinate2D(latitude: centerCoordinate.latitude+0.1, longitude: centerCoordinate.longitude-0.01)
|
|
pointFeatureAnnotation.coordinate = offsetCoordinate
|
|
mapView.addAnnotation(pointFeatureAnnotation)
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
An extention of the Mapbox map view class that offers a simplified
|
|
API for a small subset of the runtime styling APIs used in this application.
|
|
This could be extended.
|
|
*/
|
|
extension MGLMapView {
|
|
|
|
func addStyledAnnotation(_ annotation: StyledAnnotation, belowLayer layerName: String) {
|
|
if let labelsLayer = self.style?.layer(withIdentifier: "mountain-peak-label") {
|
|
let source = addSource(for: annotation)
|
|
let layer = addLayer(for: annotation, source: source)
|
|
self.style?.insertLayer(layer, below: labelsLayer)
|
|
}
|
|
}
|
|
|
|
func addStyledAnnotation(_ annotation: StyledAnnotation) {
|
|
let source = addSource(for: annotation)
|
|
let layer = addLayer(for: annotation, source: source)
|
|
self.style?.addLayer(layer)
|
|
}
|
|
|
|
func addSource(for styledAnnotation: StyledAnnotation) -> MGLSource {
|
|
let source = MGLShapeSource(identifier: UUID().uuidString, url: styledAnnotation.resource, options: nil)
|
|
self.style?.addSource(source)
|
|
return source
|
|
}
|
|
|
|
func addLayer(for styledAnnotation: StyledAnnotation, source: MGLSource) -> MGLStyleLayer {
|
|
switch styledAnnotation.type {
|
|
case .extrusion:
|
|
let layer = MGLFillExtrusionStyleLayer(identifier: styledAnnotation.identifier, source: source)
|
|
if let height = styledAnnotation.height {
|
|
layer.fillExtrusionHeight = MGLStyleValue<NSNumber>(rawValue: NSNumber(floatLiteral: Double(height)))
|
|
}
|
|
if let color = styledAnnotation.color {
|
|
layer.fillExtrusionColor = MGLStyleValue(rawValue: color)
|
|
}
|
|
if let opacity = styledAnnotation.opacity {
|
|
layer.fillExtrusionOpacity = MGLStyleValue<NSNumber>(rawValue: NSNumber(floatLiteral: Double(opacity)))
|
|
}
|
|
if let duration = styledAnnotation.transitionDuration {
|
|
layer.fillExtrusionHeightTransition = MGLTransitionMake(Double(duration), 0)
|
|
layer.fillExtrusionOpacityTransition = MGLTransitionMake(Double(duration), 0)
|
|
}
|
|
return layer
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
A struct to represent a small subset of the annotations that
|
|
are possible to add to a Mapbox map. This could be extended.
|
|
*/
|
|
struct StyledAnnotation {
|
|
|
|
enum StyledAnnotationType {
|
|
case extrusion
|
|
}
|
|
|
|
init(identifier: String, resource: URL, type: StyledAnnotationType) {
|
|
self.identifier = identifier
|
|
self.resource = resource
|
|
self.type = type
|
|
}
|
|
|
|
var identifier: String
|
|
var resource: URL
|
|
var type: StyledAnnotationType
|
|
|
|
var height: Float?
|
|
var color: UIColor?
|
|
var opacity: Float?
|
|
var transitionDuration: Float?
|
|
|
|
}
|