In this page

custom-waypoint-styling

Easily tailor the waypoint styling to suit your preferences and create a visually appealing and intuitive navigation experience.

This example shows:

  1. How to customize the UI of waypoints displayed in a route

  2. The waypoint styling is customized in CustomWaypointStylingViewController

For all code examples, refer to Navigation Code Examples

CustomWaypointStylingViewController view source

1import UIKit
2import NbmapNavigation
3import NbmapCoreNavigation
4import NbmapDirections
5import Nbmap
6
7class CustomWaypointStylingViewController: UIViewController {
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           if oldValue != nil || routes == nil || routes?.first == nil {
21               navigationMapView?.removeRoutes()
22               navigationMapView?.removeRouteDurationSymbol()
23               if let annotation = navigationMapView?.annotations?.last {
24                   navigationMapView?.removeAnnotation(annotation)
25               }
26               return
27           }
28          
29           guard let routes = routes,
30                 let current = routes.first
31           else {
32               return
33           }
34          
35           navigationMapView?.showRoutes(routes)
36           navigationMapView?.showWaypoints(current)
37           navigationMapView?.showRouteDurationSymbol(routes)
38       }
39   }
40  
41   private let startButton = UIButton()
42  
43   override func viewDidLoad() {
44       super.viewDidLoad()
45      
46       self.navigationMapView = NavigationMapView(frame: view.bounds)
47      
48       navigationMapView?.userTrackingMode = .follow
49       navigationMapView?.navigationMapDelegate = self
50       setupStartButton()
51       requestRoutes()
52      
53   }
54  
55   func setupStartButton() {
56       startButton.setTitle("Start", for: .normal)
57       startButton.layer.cornerRadius = 5
58       startButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
59       startButton.backgroundColor = .blue
60      
61       startButton.addTarget(self, action: #selector(performAction), for: .touchUpInside)
62       view.addSubview(startButton)
63       startButton.translatesAutoresizingMaskIntoConstraints = false
64       startButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50).isActive = true
65       startButton.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
66       startButton.titleLabel?.font = UIFont.systemFont(ofSize: 25)
67   }
68  
69   @objc func performAction(_ sender: Any) {
70       guard let routes = self.routes else {
71           return
72       }
73       let navigationService = NBNavigationService(routes: routes, routeIndex: 0)
74       let styles = [DayStyle(), NightStyle()]
75       let navigationOptions = NavigationOptions(styles:styles,navigationService: navigationService)
76      
77       let navigationViewController = NavigationViewController(for: routes,navigationOptions: navigationOptions)
78       navigationViewController.modalPresentationStyle = .fullScreen
79      
80       navigationViewController.delegate = self
81      
82       present(navigationViewController, animated: true, completion: nil)
83   }
84  
85   func requestRoutes(){
86       let origin = CLLocation(latitude: 37.775252, longitude: -122.416082)
87       let firstWaypoint = CLLocation(latitude: 37.779196, longitude: -122.410833)
88       let secondWaypoint = CLLocation(latitude: 37.777342, longitude: -122.404094)
89      
90       let options = NavigationRouteOptions(locations: [origin,firstWaypoint,secondWaypoint])
91       Directions.shared.calculate(options) { [weak self] routes, error in
92           guard let weakSelf = self else {
93               return
94           }
95           guard error == nil else {
96               print(error!)
97               return
98           }
99          
100           guard let routes = routes else { return }
101           weakSelf.routes = routes
102       }
103   }
104  
105  
106   func customShape(for waypoints: [Waypoint], legIndex: Int) -> NGLShape? {
107       var features = [NGLPointFeature]()
108      
109       for (waypointIndex, waypoint) in waypoints.enumerated() {
110           let feature = NGLPointFeature()
111           feature.coordinate = waypoint.coordinate
112           feature.attributes = [
113               "waypointCompleted": waypointIndex < legIndex,
114               "name": waypointIndex + 1
115           ]
116           features.append(feature)
117       }
118      
119       return NGLShapeCollectionFeature(shapes: features)
120   }
121  
122   func customWaypointCircleStyleLayer(identifier: String, source: NGLSource) -> NGLStyleLayer {
123       let circles = NGLCircleStyleLayer(identifier: identifier, source: source)
124       let opacity = NSExpression(forConditional: NSPredicate(format: "waypointCompleted == true"), trueExpression: NSExpression(forConstantValue: 0.5), falseExpression: NSExpression(forConstantValue: 1))
125      
126       circles.circleColor = NSExpression(forConstantValue: UIColor(red:0.9, green:0.9, blue:0.9, alpha:1.0))
127       circles.circleOpacity = opacity
128       circles.circleRadius = NSExpression(forConstantValue: 10)
129       circles.circleStrokeColor = NSExpression(forConstantValue: UIColor.green)
130       circles.circleStrokeWidth = NSExpression(forConstantValue: 1)
131       circles.circleStrokeOpacity = opacity
132      
133       return circles
134   }
135  
136   func customWaypointSymbolStyleLayer(identifier: String, source: NGLSource) -> NGLStyleLayer {
137       let symbol = NGLSymbolStyleLayer(identifier: identifier, source: source)
138      
139       symbol.text = NSExpression(format: "CAST(name, 'NSString')")
140       symbol.textOpacity = NSExpression(forConditional: NSPredicate(format: "waypointCompleted == true"), trueExpression: NSExpression(forConstantValue: 0.5), falseExpression: NSExpression(forConstantValue: 1))
141       symbol.textFontSize = NSExpression(forConstantValue: 10)
142       symbol.textHaloWidth = NSExpression(forConstantValue: 0.25)
143       symbol.textHaloColor = NSExpression(forConstantValue: UIColor.blue)
144      
145       return symbol
146   }
147  
148}
149
150extension CustomWaypointStylingViewController: NavigationMapViewDelegate {
151  
152   func navigationMapView(_ mapView: NavigationMapView, waypointStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
153       return customWaypointCircleStyleLayer(identifier: identifier, source: source)
154   }
155  
156   func navigationMapView(_ mapView: NavigationMapView, waypointSymbolStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
157       return customWaypointSymbolStyleLayer(identifier: identifier, source: source)
158   }
159  
160   func navigationMapView(_ mapView: NavigationMapView, shapeFor waypoints: [Waypoint], legIndex: Int) -> NGLShape? {
161       return customShape(for: waypoints, legIndex: legIndex)
162   }
163}
164
165extension CustomWaypointStylingViewController: NavigationViewControllerDelegate {
166   func navigationViewController(_ navigationViewController: NavigationViewController, waypointStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
167       return customWaypointCircleStyleLayer(identifier: identifier, source: source)
168   }
169  
170   func navigationViewController(_ navigationViewController: NavigationViewController, waypointSymbolStyleLayerWithIdentifier identifier: String, source: NGLSource) -> NGLStyleLayer? {
171       return customWaypointSymbolStyleLayer(identifier: identifier, source: source)
172   }
173  
174   func navigationViewController(_ navigationViewController: NavigationViewController, shapeFor waypoints: [Waypoint], legIndex: Int) -> NGLShape? {
175       return customShape(for: waypoints, legIndex: legIndex)
176   }
177  
178}

The code example is for a CustomWaypointStylingViewController class. This class is used to customize the UI of waypoints displayed in a route. The class does this by overriding the navigationMapView(_:waypointStyleLayerWithIdentifier:source:), navigationMapView**(:waypointSymbolStyleLayerWithIdentifier:source:)**, and **navigationMapView(:shapeFor:legIndex:)** methods. The navigationMapView(_:waypointStyleLayerWithIdentifier:source:) method is used to customize the style of the waypoint circle. The method takes three parameters:

  1. mapView: The NavigationMapView instance that is displaying the route.
  2. identifier: The identifier of the style layer.
  3. source: The source of the style layer.

The method returns a NGLStyleLayer instance that represents the custom style of the waypoint circle. The NGLStyleLayer instance can be used to specify the color, opacity, radius, and stroke of the waypoint circle.

The navigationMapView(_:waypointSymbolStyleLayerWithIdentifier:source:) method is used to customize the style of the waypoint symbol. The method takes three parameters:

  1. mapView: The NavigationMapView instance that is displaying the route.

  2. identifier: The identifier of the style layer.

  3. source: The source of the style layer.

The method returns a NGLStyleLayer instance that represents the custom style of the waypoint symbol. The NGLStyleLayer instance can be used to specify the text, opacity, font size, halo width, and halo color of the waypoint symbol.

The navigationMapView(_:shapeFor:legIndex:) method is used to customize the shape of the waypoints. The method takes three parameters:

  1. mapView: The NavigationMapView instance that is displaying the route.

  2. waypoints: The waypoints that are being displayed.

  3. egIndex: The index of the current leg.

The method returns a NGLShape instance that represents the custom shape of the waypoints. The NGLShape instance can be used to specify the coordinates of the waypoints.

By overriding these methods, you can customize the UI of waypoints displayed in a route. Here are some examples of how you can use the CustomWaypointStylingViewController class to customize the UI of waypoints:

  1. You can change the color of the waypoint circle.

  2. You can change the opacity of the waypoint circle.

  3. You can change the radius of the waypoint circle.

  4. You can change the stroke of the waypoint circle.

  5. You can change the text of the waypoint symbol.

  6. You can change the opacity of the waypoint symbol.

  7. You can change the font size of the waypoint symbol.

  8. You can change the halo width of the waypoint symbol.

  9. You can change the halo color of the waypoint symbol.

  10. You can change the coordinates of the waypoints.

DIDN'T FIND WHAT YOU LOOKING FOR?