Instantly share code, notes, and snippets.
Last active
July 28, 2021 20:49
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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