Skip to content

Instantly share code, notes, and snippets.

@johnnewman
Last active January 7, 2022 16:46
Show Gist options
  • Save johnnewman/29e4a2acec1a3fc5013a337793201ae3 to your computer and use it in GitHub Desktop.
Save johnnewman/29e4a2acec1a3fc5013a337793201ae3 to your computer and use it in GitHub Desktop.
This gist shows how the MapView's camera centering doesn't work properly until an indeterminate time after the map is presented
//
// ViewController.swift
// MapboxSample
//
// Created by John Newman on 2/07/22.
//
// Mapbox SDK v10.2.0-rc.1 and 10.2.0
//
// The map will successfully frame the camera:
// - always after the DispatchQueue.main.asyncAfter(deadline: .now() + 3) executes
// - if viewDidLayoutSubviews attempts to move the map camera, which delays the mapLoaded event. When mapLoaded does execute later, it can successfully frame the map. (This seems similar to the dispatch after 3 seconds.)
// - if you modify this code to supply a nil cameraOptions to the MapInitOptions
// The map will not successfully frame the camera:
// - when attempted immediately after the map is added to the view hierarchy
// - when attempted after the mapLoaded event (assuming setting the camera in viewDidLayoutSubviews did not delay execution of mapLoaded.)
// - when attempted in viewDidLayoutSubviews
//
import UIKit
import MapboxMaps
class ViewController: UIViewController {
let accessToken: String = "Access Token Goes Here"
var testCoordinates: [CLLocationCoordinate2D] {
[
CLLocationCoordinate2D(latitude: 48.6739882896445, longitude: -121.245782375336),
CLLocationCoordinate2D(latitude: 48.69067, longitude: -121.0992),
CLLocationCoordinate2D(latitude: 48.6433552, longitude: -120.8436691),
CLLocationCoordinate2D(latitude: 48.759631, longitude: -121.186681),
CLLocationCoordinate2D(latitude: 48.675, longitude: -121.261111),
CLLocationCoordinate2D(latitude: 48.7175349, longitude: -121.1469557),
CLLocationCoordinate2D(latitude: 48.714167, longitude: -121.131111),
CLLocationCoordinate2D(latitude: 48.6763, longitude: -121.23715),
CLLocationCoordinate2D(latitude: 48.5275299079636, longitude: -121.431330113956),
CLLocationCoordinate2D(latitude: 48.527619, longitude: -121.4495729),
CLLocationCoordinate2D(latitude: 48.504155, longitude: -121.531607),
CLLocationCoordinate2D(latitude: 48.846432, longitude: -121.692445),
CLLocationCoordinate2D(latitude: 48.923402, longitude: -121.015885)
]
}
var padding: UIEdgeInsets {
UIEdgeInsets(top: 75.0, left: 46.0, bottom: 118.0, right: 46.0)
}
var mapView: MapView!
override func viewDidLoad() {
super.viewDidLoad()
let camera = CameraOptions(zoom: 13)
let resourceOptions = ResourceOptions(accessToken: accessToken, tileStore: .default)
let mapInitOptions = MapInitOptions(resourceOptions: resourceOptions, cameraOptions: camera, styleURI: .streets)
mapView = MapView(frame: view.bounds, mapInitOptions: mapInitOptions)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
// Try setting the camera immediately after initializing the map. This will always fail.
print("Immediately setting camera.")
attemptToCenterCamera()
// Try setting the camera afer 3 seconds.
// Uncomment this and on my wifi & hardware, the map is always properly famed.
// DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
// print("Setting camera after 3 seconds.")
// self.attemptToCenterCamera()
// }
mapView.mapboxMap.onNext(.mapLoaded) { [weak self] _ in
self?.addAnnotations()
// Try setting the camera after the map loads.
print("Setting camera after mapLoaded event.")
self?.attemptToCenterCamera()
}
}
// If you uncomment this, when viewDidLayoutSubviews calls `attemptToCenterCamera()`, the camera will center
// over the ocean. However, this will happen before the above mapLoaded event executes (at least on my wifi).
// Since mapLoaded will be delayed, when it does execute, the time passed will be enough to properly frame
// the map when the mapLoaded handler's `self?.attemptToCenterCamera()` executes.
// override func viewDidLayoutSubviews() {
// super.viewDidLayoutSubviews()
// print("Setting camera in viewDidLayoutSubviews()")
// attemptToCenterCamera()
// }
func attemptToCenterCamera() {
let camera = self.mapView.mapboxMap.camera(
for: self.testCoordinates,
padding: self.padding,
bearing: nil,
pitch: nil
)
self.mapView.mapboxMap.setCamera(to: camera)
}
// This is for demo purposes to visualize the coordinates we are attempting to frame the camera around.
func addAnnotations() {
let iconSize = CGSize(width: 30, height: 30)
let icon = UIGraphicsImageRenderer(size: iconSize).image { context in
UIColor.red.setFill()
context.cgContext.fillEllipse(in: .init(origin: .zero, size: iconSize))
}
let pointManager = mapView.annotations.makePointAnnotationManager()
pointManager.annotations = testCoordinates.map {
var annotation = PointAnnotation(coordinate: $0)
annotation.image = .init(image: icon, name: "point_icon")
return annotation
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment