Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* `CarPlayManager(styles:directions:eventsManager:)` also allows you to pass in a custom `Directions` object to use when calculating routes. ([#1834](https://github.com/mapbox/mapbox-navigation-ios/pull/1834/))
* Removed the `StyleManager(_:)` initializer. After initializing a `StyleManager` object, set the `StyleManager.delegate` property to ensure that the style manager’s settings take effect. ([#1836](https://github.com/mapbox/mapbox-navigation-ios/pull/1836))
* Some additional members of `CarPlayManager` are now accessible in Objective-C code. ([#1836](https://github.com/mapbox/mapbox-navigation-ios/pull/1836))
* Fixed an issue where the user puck pointed away from the route line during turn-by-turn navigation in CarPlay. The map’s vanishing point now accounts for safe area insets, including the side maneuver view. ([#1845](https://github.com/mapbox/mapbox-navigation-ios/pull/1845))

### Other changes

Expand Down
39 changes: 38 additions & 1 deletion MapboxNavigation/CarPlayNavigationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class CarPlayNavigationViewController: UIViewController {
var navService: NavigationService
var mapView: NavigationMapView?
let shieldHeight: CGFloat = 16
var mapViewLeftSafeAreaBalancingConstraint: NSLayoutConstraint?
var mapViewRightSafeAreaBalancingConstraint: NSLayoutConstraint?

var carSession: CPNavigationSession!
var mapTemplate: CPMapTemplate
Expand Down Expand Up @@ -90,18 +92,30 @@ public class CarPlayNavigationViewController: UIViewController {
super.viewDidLoad()

let mapView = NavigationMapView(frame: view.bounds)
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
mapView.translatesAutoresizingMaskIntoConstraints = false
mapView.compassView.isHidden = true
mapView.logoView.isHidden = true
mapView.attributionButton.isHidden = true

mapView.defaultAltitude = 500
mapView.zoomedOutMotorwayAltitude = 1000
mapView.longManeuverDistance = 500

mapView.navigationMapDelegate = self

self.mapView = mapView
view.addSubview(mapView)

// These constraints don’t account for language direction, because the
// safe area insets are nondirectional and may be affected by the side
// on which the driver is sitting.
mapViewRightSafeAreaBalancingConstraint = NSLayoutConstraint(item: mapView, attribute: .left, relatedBy: .equal, toItem: view, attribute: .left, multiplier: 1, constant: 0)
view.addConstraint(mapViewRightSafeAreaBalancingConstraint!)
mapViewLeftSafeAreaBalancingConstraint = NSLayoutConstraint(item: mapView, attribute: .right, relatedBy: .equal, toItem: view, attribute: .right, multiplier: 1, constant: 0)
view.addConstraint(mapViewLeftSafeAreaBalancingConstraint!)
view.addConstraint(NSLayoutConstraint(item: mapView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0))
view.addConstraint(NSLayoutConstraint(item: mapView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0))

styleObservation = mapView.observe(\.style, options: .new) { [weak self] (mapView, change) in
guard change.newValue != nil else {
return
Expand Down Expand Up @@ -148,6 +162,12 @@ public class CarPlayNavigationViewController: UIViewController {
}

previousSafeAreaInsets = view.safeAreaInsets

// Adjust the map’s vanishing point to counterbalance the side maneuver panels by extending the view off beyond the other side of the screen.
if let mapView = mapView {
mapViewRightSafeAreaBalancingConstraint?.constant = -mapView.safeArea.right
mapViewLeftSafeAreaBalancingConstraint?.constant = mapView.safeArea.left

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m still a bit concerned about this fix, because for some reason the right safe area inset seems to contradict the behavior of the map buttons on the right. For example, the safe area insets look like this when the navigation bar and map buttons are shown:

(UIEdgeInsets) $R6 = {
  top = 0
  left = 148
  bottom = 0
  right = 0
}

but like this when the navigation bar and map buttons are hidden:

(UIEdgeInsets) $R8 = {
  top = 44
  left = 148
  bottom = 0
  right = 38
}

As a result, the puck ends up slightly too far to the left when the buttons are hidden and too far to the right when the buttons are shown. Even so, at least the puck and vanishing point are aligned, so I guess addressing this issue can be tail work.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

→ #1849

}
}

/**
Expand Down Expand Up @@ -420,6 +440,23 @@ public class CarPlayNavigationViewController: UIViewController {
}
}

@available(iOS 12.0, *)
extension CarPlayNavigationViewController: NavigationMapViewDelegate {
public func navigationMapViewUserAnchorPoint(_ mapView: NavigationMapView) -> CGPoint {
// Inset by the content inset to avoid application-defined content.
var contentFrame = UIEdgeInsetsInsetRect(mapView.bounds, mapView.contentInset)

// Avoid letting the puck go partially off-screen, and add a comfortable padding beyond that.
let courseViewBounds = mapView.userCourseView?.bounds ?? .zero
contentFrame = contentFrame.insetBy(dx: min(NavigationMapView.courseViewMinimumInsets.left + courseViewBounds.width / 2.0, contentFrame.width / 2.0),
dy: min(NavigationMapView.courseViewMinimumInsets.top + courseViewBounds.height / 2.0, contentFrame.height / 2.0))

// Get the bottom-center of the remaining frame.
assert(!contentFrame.isInfinite)
return CGPoint(x: contentFrame.midX, y: contentFrame.maxY)
}
}

@available(iOS 12.0, *)
extension CarPlayNavigationViewController: StyleManagerDelegate {
public func location(for styleManager: StyleManager) -> CLLocation? {
Expand Down
10 changes: 7 additions & 3 deletions MapboxNavigation/NavigationMapView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
}
}

/**
The minimum default insets from the content frame to the edges of the user course view.
*/
static let courseViewMinimumInsets = UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50)

/**
Center point of the user course view in screen coordinates relative to the map view.
Expand All @@ -140,14 +144,14 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate {
return anchorPoint
}

// Inset by the safe area to avoid notches or CarPlay template content.
// Inset by the safe area to avoid notches.
// Inset by the content inset to avoid application-defined content.
var contentFrame = UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(bounds, safeArea), contentInset)

// Avoid letting the puck go partially off-screen, and add a comfortable padding beyond that.
let courseViewBounds = userCourseView?.bounds ?? .zero
contentFrame = contentFrame.insetBy(dx: min(50 + courseViewBounds.width / 2.0, contentFrame.width / 2.0),
dy: min(50 + courseViewBounds.height / 2.0, contentFrame.height / 2.0))
contentFrame = contentFrame.insetBy(dx: min(NavigationMapView.courseViewMinimumInsets.left + courseViewBounds.width / 2.0, contentFrame.width / 2.0),
dy: min(NavigationMapView.courseViewMinimumInsets.top + courseViewBounds.height / 2.0, contentFrame.height / 2.0))

// Get the bottom-center of the remaining frame.
assert(!contentFrame.isInfinite)
Expand Down