Skip to content

Instantly share code, notes, and snippets.

@johnnewman
Last active July 28, 2021 20:49
Show Gist options
  • Save johnnewman/b2e634c51dbfc27bfbe5f565ee7cd0b6 to your computer and use it in GitHub Desktop.
Save johnnewman/b2e634c51dbfc27bfbe5f565ee7cd0b6 to your computer and use it in GitHub Desktop.
Code to reproduce a Mapbox Navigation bug where polylines disappear from the map when transitioning to night
import MapboxDirections
import MapboxCoreNavigation
import MapboxNavigation
class ViewController: UIViewController {
var mbNavigationController: NavigationViewController!
let addNavigationViewControllerAsChild = true
override func viewDidLoad() {
super.viewDidLoad()
// Define two waypoints to travel between
let origin = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.9131752, longitude: -77.0324047), name: "Mapbox")
let destination = Waypoint(coordinate: CLLocationCoordinate2D(latitude: 38.8977, longitude: -77.0365), name: "White House")
// Set options
let routeOptions = NavigationRouteOptions(waypoints: [origin, destination])
// Request a route using MapboxDirections.swift
Directions.shared.calculate(routeOptions) { (session, result) in
switch result {
case .failure(let error):
print(error.localizedDescription)
case .success(let response):
guard let route = response.routes?.first else {
return
}
// Pass the first generated route to the the NavigationViewController
let service = MapboxNavigationService(
route: route,
routeIndex: 0,
routeOptions: routeOptions,
directions: nil,
locationSource: nil,
eventsManagerType: nil,
simulating: .always,
routerType: nil)
let navigationOptions = NavigationOptions(
styles: nil,
navigationService: service,
voiceController: nil,
topBanner: nil,
bottomBanner: nil
)
self.mbNavigationController = NavigationViewController(
for: route,
routeIndex: 0,
routeOptions: routeOptions,
navigationOptions: navigationOptions
)
self.mbNavigationController.automaticallyAdjustsStyleForTimeOfDay = true
if self.addNavigationViewControllerAsChild {
// When adding as a child, day/night transitions can cause the route polyline to disappear from the map
// if the view that gets force refreshed is the superview of mbNavigationController.
// Capture the delegate so that we can customize styleManager(_:viewForApplying:).
self.mbNavigationController.styleManager.delegate = self
self.view.addSubview(self.mbNavigationController.view)
self.addChild(self.mbNavigationController)
self.mbNavigationController.didMove(toParent: self)
// If styleManager(_:viewForApplying:) returns the mbNavigationController's view, which is its default
// implementation, then we must we must use autoresizing masks instead of autolayout constraints for
// framing the child. This is because the superview of mbNavigationController's view will have its
// subviews removed and then readded via StyleManager forceRefreshAppearance(). In the default case, that
// superview is self.view.
self.mbNavigationController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
} else {
// When presenting modally, day/night transitions do not break the polyline. No need to capture the styleManager delegate.
self.mbNavigationController.modalPresentationStyle = .fullScreen
self.present(self.mbNavigationController, animated: true, completion: nil)
}
}
}
}
}
/// This extension is only used when `addNavigationViewControllerAsChild` is true.
extension ViewController: StyleManagerDelegate {
func styleManager(_ styleManager: StyleManager, viewForApplying currentStyle: Style?) -> UIView? {
// StyleManager's forceRefreshAppearance() will use the superview of whatever view is returned in this delegate.
// - if shouldReturnOneLevelHigher == true, this will end up using self.view.superview and the polyline won't disappear.
// - if shouldReturnOneLevelHigher == false, this will end up using self.view and the polyline will disappear.
let shouldReturnOneLevelHigher = false
if shouldReturnOneLevelHigher {
return self.view
} else {
// The default implementation will return mbNavigationController.view.
return mbNavigationController.styleManager(styleManager, viewForApplying: currentStyle)
}
}
func location(for styleManager: StyleManager) -> CLLocation? {
mbNavigationController.location(for: styleManager)
}
func styleManager(_ styleManager: StyleManager, didApply style: Style) {
mbNavigationController.styleManager(styleManager, didApply: style)
}
func styleManagerDidRefreshAppearance(_ styleManager: StyleManager) {
mbNavigationController.styleManagerDidRefreshAppearance(styleManager)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment