In this page

Route lines styling

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

Enhance your navigation app by customizing the style of route lines and create visually appealing navigation experiences.

This example shows:

  1. How to customize the style of Navigation route lines

For all code examples, refer to Navigation Code Examples

RouteLinesStylingViewController view source

1import UIKit
2import NbmapNavigation
3import NbmapCoreNavigation
4import NbmapDirections
5
6class RouteLinesStylingViewController: UIViewController {
7  
8   typealias ActionHandler = (UIAlertAction) -> Void
9  
10   var trafficUnknownColor: UIColor =  #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
11   var trafficLowColor: UIColor =  #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
12   var trafficModerateColor: UIColor =  #colorLiteral(red: 1, green: 0.5843137255, blue: 0, alpha: 1)
13   var trafficHeavyColor: UIColor =  #colorLiteral(red: 1, green: 0.3019607843, blue: 0.3019607843, alpha: 1)
14   var trafficSevereColor: UIColor = #colorLiteral(red: 0.5607843137, green: 0.1411764706, blue: 0.2784313725, alpha: 1)
15   var routeCasingColor: UIColor = #colorLiteral(red: 0.28, green: 0.36, blue: 0.8, alpha: 1)
16   var routeAlternateColor: UIColor = #colorLiteral(red: 1, green: 0.65, blue: 0, alpha: 1)
17   var routeAlternateCasingColor: UIColor = #colorLiteral(red: 1.0, green: 0.9, blue: 0.4, alpha: 1)
18   var traversedRouteColor: UIColor = #colorLiteral(red: 0.1843137255, green: 0.4784313725, blue: 0.7764705882, alpha: 1)
19  
20   var navigationMapView: NavigationMapView!
21  
22   var currentRouteIndex = 0 {
23       didSet {
24           showCurrentRoute()
25       }
26   }
27  
28   var currentRoute: Route? {
29       return routes?[currentRouteIndex]
30   }
31  
32   var routes: [Route]? {
33       didSet {
34          
35           guard let routes = routes,
36                 let current = routes.first
37           else {
38               navigationMapView?.removeRoutes()
39               navigationMapView?.removeRouteDurationSymbol()
40               if let annotation = navigationMapView?.annotations?.last {
41                   navigationMapView?.removeAnnotation(annotation)
42               }
43               return
44              
45           }
46          
47           navigationMapView?.showRoutes(routes)
48           navigationMapView?.showWaypoints(current)
49           navigationMapView?.showRouteDurationSymbol(routes)
50       }
51   }
52  
53   func showCurrentRoute() {
54       guard let currentRoute = currentRoute else { return }
55      
56       var routes = [currentRoute]
57       routes.append(contentsOf: self.routes!.filter {
58           $0 != currentRoute
59       })
60       navigationMapView.showRoutes(routes)
61       navigationMapView.showWaypoints(currentRoute)
62   }
63  
64   // MARK: - UIViewController lifecycle methods
65   override func viewDidLoad() {
66       super.viewDidLoad()
67      
68       setupNavigationMapView()
69       setupPerformActionBarButtonItem()
70       setupGestureRecognizers()
71   }
72  
73   // MARK: - Setting-up methods
74   func setupNavigationMapView() {
75       navigationMapView = NavigationMapView(frame: view.bounds)
76       navigationMapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
77       navigationMapView.navigationMapDelegate = self
78       navigationMapView.userTrackingMode = .follow
79      
80       view.addSubview(navigationMapView)
81   }
82  
83   func setupPerformActionBarButtonItem() {
84       let settingsBarButtonItem = UIBarButtonItem(title: NSString(string: "\u{2699}\u{0000FE0E}") as String,
85                                                   style: .plain,
86                                                   target: self,
87                                                   action: #selector(performAction))
88       settingsBarButtonItem.setTitleTextAttributes([.font: UIFont.systemFont(ofSize: 30)], for: .normal)
89       settingsBarButtonItem.setTitleTextAttributes([.font: UIFont.systemFont(ofSize: 30)], for: .highlighted)
90       navigationItem.rightBarButtonItem = settingsBarButtonItem
91   }
92  
93   @objc func performAction(_ sender: Any) {
94       let alertController = UIAlertController(title: "Perform action",
95                                               message: "Select specific action to perform it", preferredStyle: .actionSheet)
96      
97       let startNavigation: ActionHandler = { _ in self.startNavigation() }
98       let removeRoutes: ActionHandler = { _ in self.routes = nil }
99      
100       let actions: [(String, UIAlertAction.Style, ActionHandler?)] = [
101           ("Start Navigation", .default, startNavigation),
102           ("Remove Routes", .default, removeRoutes),
103           ("Cancel", .cancel, nil)
104       ]
105      
106       actions
107           .map({ payload in UIAlertAction(title: payload.0, style: payload.1, handler: payload.2) })
108           .forEach(alertController.addAction(_:))
109      
110       if let popoverController = alertController.popoverPresentationController {
111           popoverController.barButtonItem = navigationItem.rightBarButtonItem
112       }
113      
114       present(alertController, animated: true, completion: nil)
115   }
116  
117   func setupGestureRecognizers() {
118       let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(_:)))
119       navigationMapView.addGestureRecognizer(longPressGestureRecognizer)
120   }
121  
122   @objc func startNavigation() {
123       guard let routes = routes else {
124           print("Please select at least one destination coordinate to start navigation.")
125           return
126       }
127      
128       let navigationService = NBNavigationService(routes: routes, routeIndex: currentRouteIndex)
129      
130       let navigationOptions = NavigationOptions(navigationService: navigationService)
131       let navigationViewController = NavigationViewController(for: routes,navigationOptions: navigationOptions)
132       navigationViewController.delegate = self
133       navigationViewController.modalPresentationStyle = .fullScreen
134       navigationViewController.routeLineTracksTraversal = true
135       present(navigationViewController, animated: true, completion: nil)
136   }
137  
138   @objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
139       guard let navigationMapView = navigationMapView, gesture.state == .began else {
140           return
141       }
142       let coordinates = navigationMapView.convert(gesture.location(in: navigationMapView), toCoordinateFrom: navigationMapView)
143       let destination = Waypoint(coordinate: coordinates, name: "\(coordinates.latitude),\(coordinates.longitude)")
144      
145       addNewDestinationcon(coordinates: coordinates)
146      
147       guard let currentLocation =  navigationMapView.userLocation?.coordinate else { return}
148       let currentWayPoint = Waypoint.init(coordinate: currentLocation, name: "My Location")
149      
150       requestRoutes(origin: currentWayPoint, destination: destination)
151   }
152  
153   func addNewDestinationcon(coordinates: CLLocationCoordinate2D){
154       guard let mapView = navigationMapView else {
155           return
156       }
157      
158       if let annotation = mapView.annotations?.last {
159           mapView.removeAnnotation(annotation)
160       }
161      
162       let annotation = NGLPointAnnotation()
163       annotation.coordinate = coordinates
164       mapView.addAnnotation(annotation)
165   }
166  
167   func requestRoutes(origin: Waypoint, destination: Waypoint){
168      
169       let options = NavigationRouteOptions(origin: origin, destination: destination)
170      
171       Directions.shared.calculate(options) { [weak self] routes, error in
172           guard let weakSelf = self else {
173               return
174           }
175           guard error == nil else {
176               print(error!)
177               return
178           }
179          
180           guard let routes = routes else { return }
181          
182           weakSelf.routes = routes
183       }
184   }
185  
186   func routeStyleLayer(identifier: String,source: NGLSource) -> NGLStyleLayer {
187       let line = NGLLineStyleLayer(identifier: identifier, source: source)
188       line.lineWidth = NSExpression(format: "ngl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", NBRouteLineWidthByZoomLevel)
189       line.lineColor = NSExpression(format: "TERNARY(isAlternateRoute == true, %@, NGL_MATCH(congestion, 'low' , %@, 'moderate', %@, 'heavy', %@, 'severe', %@, %@))", routeAlternateColor, trafficLowColor, trafficModerateColor, trafficHeavyColor, trafficSevereColor, trafficUnknownColor)
190       line.lineOpacity = NSExpression(forConstantValue: 1)
191       line.lineCap = NSExpression(forConstantValue: "round")
192       line.lineJoin = NSExpression(forConstantValue: "round")
193      
194       return line
195   }
196  
197   func routeCasingStyleLayer(identifier: String,source: NGLSource) -> NGLStyleLayer {
198       let lineCasing = NGLLineStyleLayer(identifier: identifier, source: source)
199      
200       // Take the default line width and make it wider for the casing
201       lineCasing.lineWidth = NSExpression(format: "ngl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", NBRouteLineWidthByZoomLevel.multiplied(by: 1.3))
202      
203       lineCasing.lineColor = NSExpression(forConstantValue: routeCasingColor)
204      
205       lineCasing.lineCap = NSExpression(forConstantValue: "round")
206       lineCasing.lineJoin = NSExpression(forConstantValue: "round")
207      
208       lineCasing.lineOpacity = NSExpression(forConditional: NSPredicate(format: "isAlternateRoute == true"),
209                                             trueExpression: NSExpression(forConstantValue: 1),
210                                             falseExpression: NSExpression(forConditional: NSPredicate(format: "isCurrentLeg == true"), trueExpression: NSExpression(forConstantValue: 1), falseExpression: NSExpression(forConstantValue: 0.85)))
211      
212       return lineCasing
213   }
214}
215
216// MARK: - NavigationMapViewDelegate methods
217extension RouteLinesStylingViewController: NavigationMapViewDelegate {
218  
219   func navigationMapView(_ mapView: NavigationMapView, routeStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
220      
221       return routeStyleLayer(identifier: identifier,source: source)
222   }
223  
224   func navigationMapView(_ mapView: NavigationMapView, routeCasingStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
225       return routeCasingStyleLayer(identifier: identifier,source: source)
226   }
227}
228
229// MARK: - NavigationViewControllerDelegate methods
230extension RouteLinesStylingViewController: NavigationViewControllerDelegate {
231  
232  
233   func navigationViewControllerDidDismiss(_ navigationViewController: NavigationViewController, byCanceling canceled: Bool) {
234       dismiss(animated: true, completion: nil)
235   }
236  
237   func navigationViewController(_ navigationViewController: NavigationViewController, routeStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
238       return routeStyleLayer(identifier: identifier,source: source)
239   }
240  
241   func navigationViewController(_ navigationViewController: NavigationViewController, routeCasingStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
242       return routeCasingStyleLayer(identifier: identifier,source: source)
243   }
244}

The code first defines a number of colors that will be used to style the route lines. These colors are:

  1. trafficUnknownColor: This color will be used to style route lines when the traffic conditions are unknown.

  2. trafficLowColor: This color will be used to style route lines when the traffic conditions are light.

  3. trafficModerateColor: This color will be used to style route lines when the traffic conditions are moderate.

  4. trafficHeavyColor: This color will be used to style route lines when the traffic conditions are heavy.

  5. trafficSevereColor: This color will be used to style route lines when the traffic conditions are severe.

  6. routeCasingColor: This color will be used to style the casing of the route lines.

  7. routeAlternateColor: This color will be used to style alternate route lines.

  8. routeAlternateCasingColor: This color will be used to style the casing of alternate route lines.

  9. traversedRouteColor: This color will be used to style routes that have already been traversed.

The code then defines a function called routeStyleLayer(). This function takes two parameters: an identifier and a source.

  1. The identifier is used to identify the route style layer

  2. The source is the source of the route data.

  3. The function returns a NGLStyleLayer object that contains the style properties for the route line.

Inside the routeStyleLayer() function

  1. It first sets the lineWidth property of the NGLStyleLayer object to a value that varies depending on the zoom level. The lineWidth property controls the width of the route line.

  2. then sets the lineColor property of the NGLStyleLayer object to a value that depends on the traffic conditions and whether the route is an alternate route. The lineColor property controls the color of the route line.

  3. then sets the lineOpacity property of the NGLStyleLayer object to a value of 1. The lineOpacity property controls the opacity of the route line.

  4. then sets the lineCap property of the NGLStyleLayer object to a value of "round". The lineCap property controls the shape of the ends of the route line.

  5. then sets the lineJoin property of the NGLStyleLayer object to a value of "round". The lineJoin property controls the shape of the corners of the route line.

The code then defines a function called routeCasingStyleLayer(). This function is similar to the routeStyleLayer() function, but it styles the casing of the route lines.

  1. It sets the lineWidth property of the NGLStyleLayer object to a value that is 1.3 times the width of the route line.

  2. Then sets the lineColor property of the NGLStyleLayer object to a value of routeCasingColor.

  3. Then sets the lineCap property of the NGLStyleLayer object to a value of "round".

  4. Then sets the lineJoin property of the NGLStyleLayer object to a value of "round".

  5. Then sets the lineOpacity property of the NGLStyleLayer object to a value that depends on whether the route is an alternate route and whether it is the current route leg.

The code then implements

  1. navigationMapView(_:routeStyleLayerWithIdentifier:source:) method of the NavigationMapViewDelegate protocol. This method is called by the NavigationMapView object when it needs to create a route style layer. The method returns the NGLStyleLayer object that was created by the routeStyleLayer() function.

  2. navigationMapView(_:routeCasingStyleLayerWithIdentifier:source:) method of the NavigationMapViewDelegate protocol. This method is called by the NavigationMapView object when it needs to create a route casing style layer. The method returns the NGLStyleLayer object that was created by the routeCasingStyleLayer() function.

没找到你要找的内容?