In this page

Advanced navigation app

这篇文档目前尚未提供译文,将以原文展示。

In this example, we are going to create an App that allows users to long press on the map to add a destination to request routes and display the routes on the map, this app also enables route selection from alternative routes, lastly, users can start navigation by tapping the “Start” button, then the app will present the NavigationViewController to begin turn-by-turn navigation.

For all code examples, refer to Navigation Code Examples

AdvancedNavigationViewController view code

1import UIKit
2import NbmapNavigation
3import NbmapCoreNavigation
4import NbmapDirections
5import Nbmap
6
7class AdvancedNavigationViewController: UIViewController, NGLMapViewDelegate {
8  
9   var navigationMapView: NavigationMapView? {
10       didSet {
11           oldValue?.removeFromSuperview()
12           if let navigationMapView = navigationMapView {
13               view.insertSubview(navigationMapView, at: 0)
14           }
15       }
16   }
17  
18   var routes : [Route]? {
19       didSet {
20           guard routes != nil else{
21               startButton.isEnabled = false
22               return
23           }
24           startButton.isEnabled = true
25          
26           guard let routes = routes,
27                 let current = routes.first else { navigationMapView?.removeRoutes(); return }
28          
29           navigationMapView?.showRoutes(routes)
30           navigationMapView?.showWaypoints(current)
31           navigationMapView?.showRouteDurationSymbol(routes)
32       }
33   }
34  
35   var startButton = UIButton()
36  
37   override func viewDidLoad() {
38       super.viewDidLoad()
39      
40       self.navigationMapView = NavigationMapView(frame: view.bounds)
41      
42       navigationMapView?.userTrackingMode = .followWithHeading
43      
44       let singleTap = UILongPressGestureRecognizer(target: self, action: #selector(didLongPress(tap:)))
45       navigationMapView?.gestureRecognizers?.filter({ $0 is UILongPressGestureRecognizer }).forEach(singleTap.require(toFail:))
46       navigationMapView?.addGestureRecognizer(singleTap)
47       navigationMapView?.delegate = self
48       navigationMapView?.navigationMapDelegate = self
49      
50       setupStartButton()
51      
52       self.view.setNeedsLayout()
53      
54   }
55  
56   func setupStartButton() {
57       startButton.setTitle("Start", for: .normal)
58       startButton.layer.cornerRadius = 5
59       startButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
60       startButton.backgroundColor = .blue
61      
62       startButton.addTarget(self, action: #selector(tappedButton), for: .touchUpInside)
63       view.addSubview(startButton)
64       startButton.translatesAutoresizingMaskIntoConstraints = false
65       startButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50).isActive = true
66       startButton.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
67       startButton.titleLabel?.font = UIFont.systemFont(ofSize: 25)
68   }
69  
70   @objc func tappedButton(sender: UIButton) {
71       guard let routes = self.routes else {
72           return
73       }
74       let navigationService = NBNavigationService(routes: routes, routeIndex: 0)
75      
76       let navigationOptions = NavigationOptions(navigationService: navigationService)
77       let navigationViewController = NavigationViewController(for: routes,navigationOptions: navigationOptions)
78      
79       // Set the delegate of navigationViewController to subscribe for NavigationView's events, This is optional
80       // navigationViewController.delegate = weakSelf
81       navigationViewController.modalPresentationStyle = .fullScreen
82      
83       present(navigationViewController, animated: true, completion: nil)
84   }
85  
86   @objc func didLongPress(tap: UILongPressGestureRecognizer) {
87       guard let navigationMapView = navigationMapView, tap.state == .began else {
88           return
89       }
90       let coordinates = navigationMapView.convert(tap.location(in: navigationMapView), toCoordinateFrom: navigationMapView)
91       let destination = Waypoint(coordinate: coordinates, name: "\(coordinates.latitude),\(coordinates.longitude)")
92       addNewDestinationIcon(coordinates: coordinates)
93      
94       guard let currentLocation =  navigationMapView.userLocation?.coordinate else { return}
95       let currentWayPoint = Waypoint.init(coordinate: currentLocation, name: "My Location")
96      
97       requestRoutes(origin: currentWayPoint, destination: destination)
98   }
99  
100  
101   func addNewDestinationIcon(coordinates: CLLocationCoordinate2D){
102       guard let mapView = navigationMapView else {
103           return
104       }
105      
106       if let annotation = mapView.annotations?.last {
107           mapView.removeAnnotation(annotation)
108       }
109      
110       let annotation = NGLPointAnnotation()
111       annotation.coordinate = coordinates
112       mapView.addAnnotation(annotation)
113   }
114  
115   func requestRoutes(origin: Waypoint, destination: Waypoint){
116      
117       let options = NavigationRouteOptions(origin: origin, destination: destination)
118       /**
119        Sets whether the route contains an alternate route
120        By default, it set to `false`
121        */
122       options.includesAlternativeRoutes = true
123       /**
124        The route classes that the calculated routes will avoid.
125        We can set an array road class to avoid.  This property can be set to `.toll`,`.ferry`,`.highway`
126        By default ,  this property is set to empty
127        */
128       options.roadClassesToAvoid = [.toll,.ferry,.highway]
129       /**
130        Set up the navigation measurement unit
131        This property should be set to `.metric` or `.imperial`
132        By default,  this property is set to the unit following with the current system locale.
133        */
134       options.distanceMeasurementSystem = .imperial
135      
136       /**
137        Set specifying the primary mode of transportation for the routes.
138        This property should be set to `NBNavigationModeCar`, `NBNavigationModeAuto`, `NBNavigationModeBike`, `NBNavigationMode4W`,`NBNavigationMode2W`,`NBNavigationMode6W`, or `NBNavigationModeEscooter`. The default value of this property is `NBNavigationMode4W`,  which specifies driving directions.
139        */
140       options.profileIdentifier = NBNavigationMode.mode4W
141       /**
142        Set the departureTime of the route, By default,  it sets the current timestamp since 1970
143        */
144       options.departureTime = Int(Date().timeIntervalSince1970)
145      
146       /**
147        Set up the locale in which the route's instructions are written.
148        If you use NbmapDirections.swift with the Nbmap Directions API, this property affects the sentence contained within the `RouteStep.instructions` property, but it does not affect any road names contained in that property or other properties such as `RouteStep.name`.
149        The Navigation API can provide instructions in [a number of languages]. Set this property to `Bundle.main.preferredLocalizations.first` or `Locale.autoupdatingCurrent` to match the application's language or the system language, respectively.
150        By default, this property is set to the current system locale.
151        */
152       options.locale = Locale.autoupdatingCurrent
153      
154       /**
155        Set map options, This property may make the ETA more accurate.  If set to `NBMapOption.valhala`, shapeFormat needs to be set to `polyline`.
156        By default, the value of this property is `NBMapOption.none`
157        */
158       options.mapOption = NBMapOption.none
159       /**
160        Format of the data from which the shapes of the returned route and its steps are derived.
161       
162        This property has no effect on the returned shape objects, although the choice of format can significantly affect the size of the underlying HTTP response.
163       
164        The default value of this property is `polyline6`.
165        */
166       options.shapeFormat = .polyline6
167      
168       Directions.shared.calculate(options) { [weak self] routes, error in
169           guard let weakSelf = self else {
170               return
171           }
172           guard error == nil else {
173               print(error!)
174               return
175           }
176          
177           guard let routes = routes else { return }
178          
179          
180           // Process or display routes information.For example, display the routes, waypoints and duration symbol on the map
181           weakSelf.navigationMapView?.showRoutes(routes)
182           weakSelf.navigationMapView?.showRouteDurationSymbol(routes)
183          
184           guard let current = routes.first else { return }
185           weakSelf.navigationMapView?.showWaypoints(current)
186           weakSelf.routes = routes
187       }
188   }
189}
190
191extension AdvancedNavigationViewController: NavigationMapViewDelegate {
192   // Delegate method called when the user selects a route
193   func navigationMapView(_ mapView: NavigationMapView, didSelect route: Route) {
194       guard let routes = routes else { return }
195       guard let index = routes.firstIndex(where: { $0 == route }) else { return }
196       self.routes!.remove(at: index)
197       self.routes!.insert(route, at: 0)
198   }
199}

The code defines a custom view controller called AdvancedNavigationViewController that inherits from UIViewController and conforms to the NGLMapViewDelegate protocol. The purpose of this custom view controller is to implement an advanced navigation experience using NbmapNavigation, NbmapCoreNavigation, NbmapDirections, and Nbmap libraries.

  1. Import statements: The necessary frameworks are imported at the beginning of the file.

  2. navigationMapView: A property for the NavigationMapView instance. When its value is set, the old instance is removed from the view hierarchy, and the new one is inserted as a subview.

  3. routes: An array of Route objects. When its value is set, the start button's state is updated accordingly, and the route, waypoints, and route duration symbols are shown on the navigation map view.

  4. startButton: A UIButton that initiates navigation when tapped.

  5. viewDidLoad(): This method sets up the view controller after the view is loaded. It creates a NavigationMapView, adds a long press gesture recognizer, sets up the start button, and calls view.setNeedsLayout() to invalidate the current layout of the receiver and trigger a layout update during the next update cycle.

  6. setupStartButton(): This method configures the start button's appearance and adds a target to handle the button tap.

  7. tappedButton(sender:): The action method for the start button tap. It initializes a NBNavigationService, sets up navigation options and a NavigationViewController, and then presents the navigation view controller.

  8. didLongPress(tap:): The method that handles the long press gesture. It converts the tap location to coordinates and then adds a new destination based on the coordinates. It also makes a request for routes between the user's current location and the destination.

  9. addNewDestinationIcon(coordinates:): This method adds a new destination annotation to the navigation map view.

  10. requestRoutes(origin:destination:): This method requests routes between the given origin and destination using the specified options.

  11. An extension of AdvancedNavigationViewController that conforms to the NavigationMapViewDelegate protocol. It contains the navigationMapView(_:didSelect:) delegate method to handle when the user selects a route from the displayed routes.

ios-sdk-7
没找到你要找的内容?