Skip to content

Commit 5c545af

Browse files
authored
Add panning functionality on CarPlay. (#4288)
1 parent 6b31415 commit 5c545af

File tree

4 files changed

+47
-39
lines changed

4 files changed

+47
-39
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
### CarPlay
4949

5050
* Added the ability to display a junction image for the maneuver on CarPlay. ([#4324](https://github.com/mapbox/mapbox-navigation-ios/pull/4324))
51+
* Added the ability to pan a map view on CarPlay. ([#4288](https://github.com/mapbox/mapbox-navigation-ios/pull/4288))
5152

5253
### Other changes
5354

Sources/MapboxNavigation/CarPlayManager.swift

Lines changed: 36 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,17 @@ public class CarPlayManager: NSObject {
240240
public var navigationMapView: NavigationMapView? {
241241
return carPlayMapViewController?.navigationMapView
242242
}
243+
244+
var activeNavigationMapView: NavigationMapView? {
245+
if let carPlayNavigationViewController = carPlayNavigationViewController,
246+
let validNavigationMapView = carPlayNavigationViewController.navigationMapView {
247+
return validNavigationMapView
248+
} else if let carPlayMapViewController = carPlayMapViewController {
249+
return carPlayMapViewController.navigationMapView
250+
} else {
251+
return nil
252+
}
253+
}
243254

244255
var mapTemplateProvider: MapTemplateProvider
245256

@@ -506,18 +517,12 @@ extension CarPlayManager: CPInterfaceControllerDelegate {
506517

507518
guard interfaceController?.topTemplate == mainMapTemplate,
508519
template == interfaceController?.rootTemplate else { return }
509-
self.removeRoutesFromMap()
520+
521+
removeRoutesFromMap()
510522
}
511523

512524
public func templateWillDisappear(_ template: CPTemplate, animated: Bool) {
513525
delegate?.carPlayManager(self, templateWillDisappear: template, animated: animated)
514-
515-
guard let interfaceController = interfaceController,
516-
let topTemplate = interfaceController.topTemplate,
517-
type(of: topTemplate) == CPSearchTemplate.self ||
518-
interfaceController.templates.count == 1 else { return }
519-
520-
navigationMapView?.navigationCamera.follow()
521526
}
522527

523528
public func templateDidDisappear(_ template: CPTemplate, animated: Bool) {
@@ -857,16 +862,14 @@ extension CarPlayManager: CPMapTemplateDelegate {
857862
delegate?.carPlayManagerDidEndNavigation(self, byCanceling: false)
858863
}
859864

865+
public func mapTemplateDidBeginPanGesture(_ mapTemplate: CPMapTemplate) {
866+
// Whenever panning starts - stop any navigation camera updates.
867+
activeNavigationMapView?.navigationCamera.stop()
868+
}
869+
860870
public func mapTemplate(_ mapTemplate: CPMapTemplate, didEndPanGestureWithVelocity velocity: CGPoint) {
861-
// We want the panning surface to have "friction". If the user did not "flick" fast/hard enough, do not update the map with a final animation.
862-
guard sqrtf(Float(velocity.x * velocity.x + velocity.y * velocity.y)) > 100 else {
863-
return
864-
}
865-
866-
let decelerationRate: CGFloat = 0.9
867-
let offset = CGPoint(x: velocity.x * decelerationRate / 4,
868-
y: velocity.y * decelerationRate / 4)
869-
updatePan(by: offset, mapTemplate: mapTemplate, animated: true)
871+
// After panning is stopped - allow navigation bar dismissal.
872+
mapTemplate.automaticallyHidesNavigationBar = true
870873
}
871874

872875
public func mapTemplateDidShowPanningInterface(_ mapTemplate: CPMapTemplate) {
@@ -933,24 +936,23 @@ extension CarPlayManager: CPMapTemplateDelegate {
933936
public func mapTemplate(_ mapTemplate: CPMapTemplate,
934937
didUpdatePanGestureWithTranslation translation: CGPoint,
935938
velocity: CGPoint) {
936-
updatePan(by: translation, mapTemplate: mapTemplate, animated: false)
937-
}
938-
939-
private func updatePan(by offset: CGPoint, mapTemplate: CPMapTemplate, animated: Bool) {
940-
let navigationMapView: NavigationMapView
941-
if let carPlayNavigationViewController = carPlayNavigationViewController,
942-
let validNavigationMapView = carPlayNavigationViewController.navigationMapView,
943-
mapTemplate == carPlayNavigationViewController.mapTemplate {
944-
navigationMapView = validNavigationMapView
945-
} else if let carPlayMapViewController = carPlayMapViewController {
946-
navigationMapView = carPlayMapViewController.navigationMapView
947-
} else {
939+
// Map view panning is allowed in all states except routes preview.
940+
if currentActivity == .previewing {
948941
return
949942
}
950-
951-
let coordinate = self.coordinate(of: offset, in: navigationMapView)
952-
let cameraOptions = CameraOptions(center: coordinate)
953-
navigationMapView.mapView.camera.ease(to: cameraOptions, duration: 1.0)
943+
944+
// Continuously prevent navigation bar hiding whenever panning occurs.
945+
mapTemplate.automaticallyHidesNavigationBar = false
946+
947+
updatePan(by: translation, mapTemplate: mapTemplate)
948+
}
949+
950+
private func updatePan(by offset: CGPoint, mapTemplate: CPMapTemplate) {
951+
guard let navigationMapView = activeNavigationMapView else { return }
952+
953+
var cameraState = navigationMapView.mapView.mapboxMap.cameraState
954+
cameraState.center = coordinate(of: offset, in: navigationMapView)
955+
navigationMapView.mapView.mapboxMap.setCamera(to: CameraOptions(cameraState: cameraState))
954956
}
955957

956958
func coordinate(of offset: CGPoint, in navigationMapView: NavigationMapView) -> CLLocationCoordinate2D {
@@ -965,8 +967,7 @@ extension CarPlayManager: CPMapTemplateDelegate {
965967
// In case if `CarPlayManager.carPlayNavigationViewController` is not `nil`, it means that
966968
// active-guidance navigation is currently in progress. Is so, panning should be applied for
967969
// `NavigationMapView` instance there.
968-
guard let navigationMapView = carPlayNavigationViewController?.navigationMapView ??
969-
carPlayMapViewController?.navigationMapView else { return }
970+
guard let navigationMapView = activeNavigationMapView else { return }
970971

971972
// After `MapView` panning `NavigationCamera` should be moved to idle state to prevent any further changes.
972973
navigationMapView.navigationCamera.stop()

Sources/MapboxNavigation/CarPlayMapViewController.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,6 @@ open class CarPlayMapViewController: UIViewController {
328328
setupStyleManager()
329329
setupSpeedLimitView()
330330
setupWayNameView()
331-
navigationMapView.navigationCamera.follow()
332331
}
333332

334333
open override func viewWillAppear(_ animated: Bool) {
@@ -339,6 +338,14 @@ open class CarPlayMapViewController: UIViewController {
339338
}
340339
}
341340

341+
open override func viewDidAppear(_ animated: Bool) {
342+
super.viewDidAppear(animated)
343+
344+
// Whenever `CarPlayMapViewController` appears on a screen - switch camera to the following
345+
// mode.
346+
navigationMapView.navigationCamera.follow()
347+
}
348+
342349
@available(iOS 13.0, *)
343350
func applyStyleIfNeeded(_ contentStyle: CPContentStyle) {
344351
if contentStyle.contains(.dark) {
@@ -355,7 +362,6 @@ open class CarPlayMapViewController: UIViewController {
355362
view.setNeedsUpdateConstraints()
356363

357364
guard let routes = navigationMapView.routes, !routes.isEmpty else {
358-
navigationMapView.navigationCamera.follow()
359365
return
360366
}
361367

Sources/MapboxNavigation/CarPlayNavigationViewController.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,8 +1196,8 @@ extension CarPlayNavigationViewController: CPSessionConfigurationDelegate {
11961196
extension CarPlayNavigationViewController: CPListTemplateDelegate {
11971197

11981198
public func listTemplate(_ listTemplate: CPListTemplate,
1199-
didSelect item: CPListItem,
1200-
completionHandler: @escaping () -> Void) {
1199+
didSelect item: CPListItem,
1200+
completionHandler: @escaping () -> Void) {
12011201
// Selected a list item for switching to alternative route.
12021202
guard let userInfo = item.userInfo as? CarPlayUserInfo,
12031203
let alternativeId = userInfo[CarPlayAlternativeIDKey] as? AlternativeRoute.ID,

0 commit comments

Comments
 (0)