Custom Location Source

Customize the location data source for NavigationMapView and Navigation. Obtain location data from user tap actions on the map.

This example shows how to customize your location data source for NavigationMapView and Navigation

  • Custom your location data source for NavigationMapView, the location data value is from the user tap action on the map

  • Custom your location data source for Navigation

documentation image

For all code examples, refer to Navigation Code Examples

CustomLocationSourceViewController view source

1
import UIKit
2
import NbmapNavigation
3
import NbmapCoreNavigation
4
import Nbmap
5
6
class CustomLocationSourceViewController: UIViewController, NGLMapViewDelegate {
7
8
var navigationMapView: NavigationMapView? {
9
didSet {
10
oldValue?.removeFromSuperview()
11
if let navigationMapView = navigationMapView {
12
view.insertSubview(navigationMapView, at: 0)
13
}
14
}
15
}
16
17
var routes : [Route]? {
18
didSet {
19
guard routes != nil else{
20
startButton.isEnabled = false
21
return
22
}
23
startButton.isEnabled = true
24
}
25
}
26
27
var currentRouteIndex = 0
28
29
var startButton = UIButton()
30
31
override func viewDidLoad() {
32
super.viewDidLoad()
33
34
navigationMapView = NavigationMapView(frame: view.bounds)
35
36
navigationMapView?.locationManager = CustomMapLocationManager()
37
38
navigationMapView?.userTrackingMode = .followWithHeading
39
40
let singleTap = UILongPressGestureRecognizer(target: self, action: #selector(didLongPress(tap:)))
41
navigationMapView?.gestureRecognizers?.filter({ $0 is UILongPressGestureRecognizer }).forEach(singleTap.require(toFail:))
42
navigationMapView?.addGestureRecognizer(singleTap)
43
44
setupStartButton()
45
46
self.view.setNeedsLayout()
47
48
}
49
50
func setupStartButton() {
51
startButton.setTitle("Start", for: .normal)
52
startButton.layer.cornerRadius = 5
53
startButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
54
startButton.backgroundColor = .blue
55
56
startButton.addTarget(self, action: #selector(tappedButton), for: .touchUpInside)
57
view.addSubview(startButton)
58
startButton.translatesAutoresizingMaskIntoConstraints = false
59
startButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -50).isActive = true
60
startButton.centerXAnchor.constraint(equalTo: view.safeAreaLayoutGuide.centerXAnchor).isActive = true
61
startButton.titleLabel?.font = UIFont.systemFont(ofSize: 25)
62
}
63
64
@objc func tappedButton(sender: UIButton) {
65
guard let routes = self.routes else {
66
return
67
}
68
let navigationService = NBNavigationService(routes: routes, routeIndex: currentRouteIndex,locationSource: CustomNavigationLocationManager())
69
let navigationOptions = NavigationOptions(navigationService: navigationService)
70
71
let navigationViewController = NavigationViewController(for: routes,navigationOptions: navigationOptions)
72
navigationViewController.modalPresentationStyle = .fullScreen
73
74
present(navigationViewController, animated: true, completion: nil)
75
}
76
77
@objc func didLongPress(tap: UILongPressGestureRecognizer) {
78
guard let navigationMapView = navigationMapView, tap.state == .began else {
79
return
80
}
81
let coordinates = navigationMapView.convert(tap.location(in: navigationMapView), toCoordinateFrom: navigationMapView)
82
// Note: The destination name can be modified. The value is used in the top banner when arriving at a destination.
83
let destination = Waypoint(coordinate: coordinates, name: "\(coordinates.latitude),\(coordinates.longitude)")
84
addNewDestinationcon(coordinates: coordinates)
85
86
guard let currentLocation = navigationMapView.userLocation?.coordinate else { return}
87
let currentWayPoint = Waypoint.init(coordinate: currentLocation, name: "My Location")
88
89
requestRoutes(origin: currentWayPoint, destination: destination)
90
}
91
92
93
func addNewDestinationcon(coordinates: CLLocationCoordinate2D){
94
guard let mapView = navigationMapView else {
95
return
96
}
97
98
if let annotation = mapView.annotations?.last {
99
mapView.removeAnnotation(annotation)
100
}
101
102
let annotation = NGLPointAnnotation()
103
annotation.coordinate = coordinates
104
mapView.addAnnotation(annotation)
105
}
106
107
func requestRoutes(origin: Waypoint, destination: Waypoint){
108
109
let options = NavigationRouteOptions(origin: origin, destination: destination)
110
111
Directions.shared.calculate(options) { [weak self] routes, error in
112
guard let weakSelf = self else {
113
return
114
}
115
guard error == nil else {
116
print(error!)
117
return
118
}
119
120
guard let routes = routes else { return }
121
122
123
// Process or display routes information.For example,display the routes,waypoints and duration symbol on the map
124
weakSelf.navigationMapView?.showRoutes(routes)
125
weakSelf.navigationMapView?.showRouteDurationSymbol(routes)
126
127
guard let current = routes.first else { return }
128
weakSelf.navigationMapView?.showWaypoints(current)
129
weakSelf.routes = routes
130
}
131
}
132
}
133
134
135
CustomMapViewLocationManager View source
136
import Nbmap
137
import CoreLocation
138
class CustomMapViewLocationManager: NSObject,NGLLocationManager {
139
140
var delegate: NGLLocationManagerDelegate? {
141
didSet {
142
locationManager.delegate = self
143
}
144
}
145
146
// Replace with your own location manager
147
private let locationManager = CLLocationManager()
148
149
var headingOrientation: CLDeviceOrientation {
150
get {
151
return locationManager.headingOrientation
152
}
153
set {
154
locationManager.headingOrientation = newValue
155
}
156
}
157
158
var desiredAccuracy: CLLocationAccuracy {
159
get {
160
return locationManager.desiredAccuracy
161
}
162
set {
163
locationManager.desiredAccuracy = newValue
164
}
165
}
166
167
var authorizationStatus: CLAuthorizationStatus {
168
if #available(iOS 14.0, *) {
169
return locationManager.authorizationStatus
170
} else {
171
return CLLocationManager.authorizationStatus()
172
}
173
}
174
175
var activityType: CLActivityType {
176
get {
177
return locationManager.activityType
178
}
179
set {
180
locationManager.activityType = newValue
181
}
182
}
183
184
@available(iOS 14.0, *)
185
var accuracyAuthorization: CLAccuracyAuthorization {
186
return locationManager.accuracyAuthorization
187
}
188
189
@available(iOS 14.0, *)
190
func requestTemporaryFullAccuracyAuthorization(withPurposeKey purposeKey: String) {
191
locationManager.requestTemporaryFullAccuracyAuthorization(withPurposeKey: purposeKey)
192
}
193
194
func dismissHeadingCalibrationDisplay() {
195
locationManager.dismissHeadingCalibrationDisplay()
196
}
197
198
func requestAlwaysAuthorization() {
199
locationManager.requestAlwaysAuthorization()
200
}
201
202
func requestWhenInUseAuthorization() {
203
locationManager.requestWhenInUseAuthorization()
204
}
205
206
func startUpdatingHeading() {
207
locationManager.startUpdatingHeading()
208
}
209
210
func startUpdatingLocation() {
211
locationManager.startUpdatingLocation()
212
}
213
214
func stopUpdatingHeading() {
215
locationManager.stopUpdatingHeading()
216
}
217
218
func stopUpdatingLocation() {
219
locationManager.stopUpdatingLocation()
220
}
221
222
deinit {
223
locationManager.stopUpdatingLocation()
224
locationManager.stopUpdatingHeading()
225
locationManager.delegate = nil
226
delegate = nil
227
}
228
229
}
230
// MARK: - CLLocationManagerDelegate , Please replace with your location data source delegate
231
extension CustomMapLocationManager : CLLocationManagerDelegate {
232
233
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
234
delegate?.locationManager(self, didUpdate: locations)
235
}
236
237
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
238
delegate?.locationManager(self, didUpdate: newHeading)
239
}
240
241
func locationManagerShouldDisplayHeadingCalibration(_ manager: CLLocationManager) -> Bool {
242
return delegate?.locationManagerShouldDisplayHeadingCalibration(self) ?? false
243
}
244
245
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
246
delegate?.locationManager(self, didFailWithError: error)
247
}
248
249
@available(iOS 14.0, *)
250
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
251
delegate?.locationManagerDidChangeAuthorization(self)
252
}
253
}
254
255
256
CustomNavigationLocationManager view source
257
import NbmapCoreNavigation
258
import CoreLocation
259
class CustomNavigationLocationManager : NavigationLocationManager {
260
261
override var delegate: CLLocationManagerDelegate? {
262
didSet {
263
locationManager.delegate = self
264
}
265
}
266
267
// Replace with your own location manager
268
private let locationManager = CLLocationManager()
269
270
override var headingOrientation: CLDeviceOrientation {
271
get {
272
return locationManager.headingOrientation
273
}
274
set {
275
locationManager.headingOrientation = newValue
276
}
277
}
278
279
override var desiredAccuracy: CLLocationAccuracy {
280
get {
281
return locationManager.desiredAccuracy
282
}
283
set {
284
locationManager.desiredAccuracy = newValue
285
}
286
}
287
288
override var authorizationStatus: CLAuthorizationStatus {
289
if #available(iOS 14.0, *) {
290
return locationManager.authorizationStatus
291
} else {
292
return CLLocationManager.authorizationStatus()
293
}
294
}
295
296
override var activityType: CLActivityType {
297
get {
298
return locationManager.activityType
299
}
300
set {
301
locationManager.activityType = newValue
302
}
303
}
304
305
@available(iOS 14.0, *)
306
override var accuracyAuthorization: CLAccuracyAuthorization {
307
return locationManager.accuracyAuthorization
308
}
309
310
@available(iOS 14.0, *)
311
override func requestTemporaryFullAccuracyAuthorization(withPurposeKey purposeKey: String) {
312
locationManager.requestTemporaryFullAccuracyAuthorization(withPurposeKey: purposeKey)
313
}
314
315
override func dismissHeadingCalibrationDisplay() {
316
locationManager.dismissHeadingCalibrationDisplay()
317
}
318
319
override func requestAlwaysAuthorization() {
320
locationManager.requestAlwaysAuthorization()
321
}
322
323
override func requestWhenInUseAuthorization() {
324
locationManager.requestWhenInUseAuthorization()
325
}
326
327
override func startUpdatingHeading() {
328
locationManager.startUpdatingHeading()
329
}
330
331
override func startUpdatingLocation() {
332
locationManager.startUpdatingLocation()
333
}
334
335
override func stopUpdatingHeading() {
336
locationManager.stopUpdatingHeading()
337
}
338
339
override func stopUpdatingLocation() {
340
locationManager.stopUpdatingLocation()
341
}
342
343
deinit {
344
locationManager.stopUpdatingLocation()
345
locationManager.stopUpdatingHeading()
346
locationManager.delegate = nil
347
delegate = nil
348
}
349
350
}
351
// MARK: - CLLocationManagerDelegate
352
extension CustomNavigationLocationManager : CLLocationManagerDelegate {
353
354
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
355
delegate?.locationManager!(self, didUpdateLocations: locations)
356
}
357
358
func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
359
delegate?.locationManager!(self, didUpdateHeading: newHeading)
360
}
361
362
func locationManagerShouldDisplayHeadingCalibration(_ manager: CLLocationManager) -> Bool {
363
return delegate?.locationManagerShouldDisplayHeadingCalibration!(self) ?? false
364
}
365
366
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
367
delegate?.locationManager!(self, didFailWithError: error)
368
}
369
370
@available(iOS 14.0, *)
371
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
372
delegate?.locationManagerDidChangeAuthorization!(self)
373
}
374
}
375