From 94aa083e6c458cfe2c3fa9417ff2bd3ad1dcc540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Mon, 19 Nov 2018 19:32:32 -0800 Subject: [PATCH 1/3] Fixed CarPlay navigation map vanishing point --- CHANGELOG.md | 1 + .../CarPlayNavigationViewController.swift | 14 +++++++++++++- MapboxNavigation/NavigationMapView.swift | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96b66e29778..1a4ff084657 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/MapboxNavigation/CarPlayNavigationViewController.swift b/MapboxNavigation/CarPlayNavigationViewController.swift index 39a1779440b..b2e32b202e2 100644 --- a/MapboxNavigation/CarPlayNavigationViewController.swift +++ b/MapboxNavigation/CarPlayNavigationViewController.swift @@ -24,6 +24,7 @@ public class CarPlayNavigationViewController: UIViewController { var navService: NavigationService var mapView: NavigationMapView? let shieldHeight: CGFloat = 16 + var mapViewSafeAreaBalancingConstraint: NSLayoutConstraint? var carSession: CPNavigationSession! var mapTemplate: CPMapTemplate @@ -90,7 +91,7 @@ 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 @@ -102,6 +103,12 @@ public class CarPlayNavigationViewController: UIViewController { self.mapView = mapView view.addSubview(mapView) + view.addConstraint(NSLayoutConstraint(item: mapView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0)) + mapViewSafeAreaBalancingConstraint = NSLayoutConstraint(item: mapView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0) + view.addConstraint(mapViewSafeAreaBalancingConstraint!) + 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 @@ -148,6 +155,11 @@ 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 { + mapViewSafeAreaBalancingConstraint?.constant = mapView.safeArea.left - mapView.safeArea.right + } } /** diff --git a/MapboxNavigation/NavigationMapView.swift b/MapboxNavigation/NavigationMapView.swift index 3f485d606d9..851a3dcb194 100644 --- a/MapboxNavigation/NavigationMapView.swift +++ b/MapboxNavigation/NavigationMapView.swift @@ -142,7 +142,7 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate { // Inset by the safe area to avoid notches or CarPlay template content. // Inset by the content inset to avoid application-defined content. - var contentFrame = UIEdgeInsetsInsetRect(UIEdgeInsetsInsetRect(bounds, safeArea), contentInset) + var contentFrame = UIEdgeInsetsInsetRect(bounds, contentInset) // Avoid letting the puck go partially off-screen, and add a comfortable padding beyond that. let courseViewBounds = userCourseView?.bounds ?? .zero From c0183054c3280da3b028062f7b773f33bc71b5ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Wed, 21 Nov 2018 13:22:50 -0800 Subject: [PATCH 2/3] Limit vanishing point fix to CarPlay MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit NavigationMapView can’t assume that its containing view controller is widening it to account for safe area insets. Balanced out the width adjustment so that the fix also applies when the status bar is on the right side of the screen. --- .../CarPlayNavigationViewController.swift | 35 ++++++++++++++++--- MapboxNavigation/NavigationMapView.swift | 4 +-- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/MapboxNavigation/CarPlayNavigationViewController.swift b/MapboxNavigation/CarPlayNavigationViewController.swift index b2e32b202e2..5ff3fb596a2 100644 --- a/MapboxNavigation/CarPlayNavigationViewController.swift +++ b/MapboxNavigation/CarPlayNavigationViewController.swift @@ -24,7 +24,8 @@ public class CarPlayNavigationViewController: UIViewController { var navService: NavigationService var mapView: NavigationMapView? let shieldHeight: CGFloat = 16 - var mapViewSafeAreaBalancingConstraint: NSLayoutConstraint? + var mapViewLeftSafeAreaBalancingConstraint: NSLayoutConstraint? + var mapViewRightSafeAreaBalancingConstraint: NSLayoutConstraint? var carSession: CPNavigationSession! var mapTemplate: CPMapTemplate @@ -99,13 +100,19 @@ public class CarPlayNavigationViewController: UIViewController { mapView.defaultAltitude = 500 mapView.zoomedOutMotorwayAltitude = 1000 mapView.longManeuverDistance = 500 + + mapView.navigationMapDelegate = self self.mapView = mapView view.addSubview(mapView) - view.addConstraint(NSLayoutConstraint(item: mapView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0)) - mapViewSafeAreaBalancingConstraint = NSLayoutConstraint(item: mapView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0) - view.addConstraint(mapViewSafeAreaBalancingConstraint!) + // 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)) @@ -158,7 +165,8 @@ public class CarPlayNavigationViewController: UIViewController { // 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 { - mapViewSafeAreaBalancingConstraint?.constant = mapView.safeArea.left - mapView.safeArea.right + mapViewRightSafeAreaBalancingConstraint?.constant = -mapView.safeArea.right + mapViewLeftSafeAreaBalancingConstraint?.constant = mapView.safeArea.left } } @@ -432,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(50 + courseViewBounds.width / 2.0, contentFrame.width / 2.0), + dy: min(50 + 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? { diff --git a/MapboxNavigation/NavigationMapView.swift b/MapboxNavigation/NavigationMapView.swift index 851a3dcb194..19897dcc096 100644 --- a/MapboxNavigation/NavigationMapView.swift +++ b/MapboxNavigation/NavigationMapView.swift @@ -140,9 +140,9 @@ 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(bounds, contentInset) + 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 From d080cbc8f847bd71c9d9169efba345250816ec6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Wed, 21 Nov 2018 15:02:18 -0800 Subject: [PATCH 3/3] Factored out course view minimum insets --- MapboxNavigation/CarPlayNavigationViewController.swift | 4 ++-- MapboxNavigation/NavigationMapView.swift | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/MapboxNavigation/CarPlayNavigationViewController.swift b/MapboxNavigation/CarPlayNavigationViewController.swift index 5ff3fb596a2..f669e114f4f 100644 --- a/MapboxNavigation/CarPlayNavigationViewController.swift +++ b/MapboxNavigation/CarPlayNavigationViewController.swift @@ -448,8 +448,8 @@ extension CarPlayNavigationViewController: NavigationMapViewDelegate { // 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(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) diff --git a/MapboxNavigation/NavigationMapView.swift b/MapboxNavigation/NavigationMapView.swift index 19897dcc096..6a3856d4e1b 100644 --- a/MapboxNavigation/NavigationMapView.swift +++ b/MapboxNavigation/NavigationMapView.swift @@ -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. @@ -146,8 +150,8 @@ open class NavigationMapView: MGLMapView, UIGestureRecognizerDelegate { // 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)