Display User Location

This section of the iOS Maps SDK provides developers with the necessary tools and guidelines to incorporate user location functionality into their applications. This functionality allows users to see their current location on the map, providing a more personalized and interactive experience.

Permissions

This section explains the importance of obtaining the necessary location permissions from the user. It provides information on how to request location permissions and handle user responses. Ensuring that the appropriate permissions are obtained is crucial for accessing and displaying the user's location accurately and securely.

Add the following to the info.plist

1
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
2
<string>YOUR_DESCRIPTION</string>
3
<key>NSLocationAlwaysUsageDescription</key>
4
<string>YOUR_DESCRIPTION</string>

Replace YOUR_DESCRIPTION with a short description of the location information your application uses.

Permission requests are automatically triggered by the Maps SDK when obtaining location information

Location provider/Component

docs-image

You can use the following code to display the current location on the map. mapView.showsUserLocation = true

You can also use your own location component. Here is an example of MapView using a custom Location component.

  1. Create custom MapLocationManager

    1
    import Nbmap
    2
    import CoreLocation
    3
    class CustomMapLocationManager: NSObject,NGLLocationManager {
    4
    5
    var delegate: NGLLocationManagerDelegate? {
    6
    didSet {
    7
    locationManager.delegate = self
    8
    }
    9
    }
    10
    11
    // Replay with your own location manager
    12
    private let locationManager = CLLocationManager()
    13
    14
    var headingOrientation: CLDeviceOrientation {
    15
    get {
    16
    return locationManager.headingOrientation
    17
    }
    18
    set {
    19
    locationManager.headingOrientation = newValue
    20
    }
    21
    }
    22
    23
    var desiredAccuracy: CLLocationAccuracy {
    24
    get {
    25
    return locationManager.desiredAccuracy
    26
    }
    27
    set {
    28
    locationManager.desiredAccuracy = newValue
    29
    }
    30
    }
    31
    32
    var authorizationStatus: CLAuthorizationStatus {
    33
    if #available(iOS 14.0, *) {
    34
    return locationManager.authorizationStatus
    35
    } else {
    36
    return CLLocationManager.authorizationStatus()
    37
    }
    38
    }
    39
    40
    var activityType: CLActivityType {
    41
    get {
    42
    return locationManager.activityType
    43
    }
    44
    set {
    45
    locationManager.activityType = newValue
    46
    }
    47
    }
    48
    49
    @available(iOS 14.0, *)
    50
    var accuracyAuthorization: CLAccuracyAuthorization {
    51
    return locationManager.accuracyAuthorization
    52
    }
    53
    54
    @available(iOS 14.0, *)
    55
    func requestTemporaryFullAccuracyAuthorization(withPurposeKey purposeKey: String) {
    56
    locationManager.requestTemporaryFullAccuracyAuthorization(withPurposeKey: purposeKey)
    57
    }
    58
    59
    func dismissHeadingCalibrationDisplay() {
    60
    locationManager.dismissHeadingCalibrationDisplay()
    61
    }
    62
    63
    func requestAlwaysAuthorization() {
    64
    locationManager.requestAlwaysAuthorization()
    65
    }
    66
    67
    func requestWhenInUseAuthorization() {
    68
    locationManager.requestWhenInUseAuthorization()
    69
    }
    70
    71
    func startUpdatingHeading() {
    72
    locationManager.startUpdatingHeading()
    73
    }
    74
    75
    func startUpdatingLocation() {
    76
    locationManager.startUpdatingLocation()
    77
    }
    78
    79
    func stopUpdatingHeading() {
    80
    locationManager.stopUpdatingHeading()
    81
    }
    82
    83
    func stopUpdatingLocation() {
    84
    locationManager.stopUpdatingLocation()
    85
    }
    86
    87
    deinit {
    88
    locationManager.stopUpdatingLocation()
    89
    locationManager.stopUpdatingHeading()
    90
    locationManager.delegate = nil
    91
    delegate = nil
    92
    }
    93
    94
    }
    95
    // MARK: - CLLocationManagerDelegate
    96
    extension CustomMapLocationManager : CLLocationManagerDelegate {
    97
    98
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    99
    delegate?.locationManager(self, didUpdate: locations)
    100
    }
    101
    102
    func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) {
    103
    delegate?.locationManager(self, didUpdate: newHeading)
    104
    }
    105
    106
    func locationManagerShouldDisplayHeadingCalibration(_ manager: CLLocationManager) -> Bool {
    107
    return delegate?.locationManagerShouldDisplayHeadingCalibration(self) ?? false
    108
    }
    109
    110
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
    111
    delegate?.locationManager(self, didFailWithError: error)
    112
    }
    113
    114
    115
    @available(iOS 14.0, *)
    116
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
    117
    delegate?.locationManagerDidChangeAuthorization(self)
    118
    }
    119
    }
  2. Use custom location manager

    1
    import Foundation
    2
    import UIKit
    3
    import Nbmap
    4
    class CustomLocationSourceViewController: UIViewController {
    5
    var nbMapView: NGLMapView! {
    6
    didSet {
    7
    oldValue?.removeFromSuperview()
    8
    if let mapView = nbMapView {
    9
    view.insertSubview(mapView, at: 0)
    10
    }
    11
    }
    12
    }
    13
    override func viewDidLoad() {
    14
    super.viewDidLoad()
    15
    nbMapView = NGLMapView(frame:self.view.bounds)
    16
    nbMapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    17
    18
    /**
    19
    Custom the location source , The locationManager that this map view uses to start and stop the delivery of
    20
    location-related updates.
    21
    To receive the current user location, implement the
    22
    `-[NGLMapViewDelegate mapView:didUpdateUserLocation:]` and
    23
    `-[NGLMapViewDelegate mapView:didFailToLocateUserWithError:]` methods.
    24
    If setting this property to `nil` or if no custom manager is provided this
    25
    property is set to the default location manager.
    26
    `NGLMapView` uses a default location manager. If you want to substitute your
    27
    own location manager, you should do so by setting this property before setting
    28
    `showsUserLocation` to `YES`. To restore the default location manager,
    29
    set this property to `nil`.
    30
    */
    31
    nbMapView.locationManager = CustomMapLocationManager()
    32
    nbMapView.showsUserLocation = true
    33
    nbMapView.userTrackingMode = .follow
    34
    }
    35
    }

Location Puck

The location puck refers to the graphical representation of the user's current location on the map. This subsection discusses how to customize and style the location puck to match the app's design and provide a clear visual indication of the user's position on the map. Developers can learn how to adjust the size, color, and shape of the location puck to meet their application's requirements.

docs-image

Code example: show user location on the map and customise puck view

1
import UIKit
2
import Nbmap
3
class CustomPuckViewController: UIViewController {
4
var nbMapView: NGLMapView! {
5
didSet {
6
oldValue?.removeFromSuperview()
7
if let mapView = nbMapView {
8
view.insertSubview(mapView, at: 0)
9
}
10
}
11
}
12
override func viewDidLoad() {
13
super.viewDidLoad()
14
nbMapView = NGLMapView(frame:self.view.bounds)
15
nbMapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
16
nbMapView.delegate = self
17
nbMapView.userTrackingMode = .follow
18
}
19
}
20
// MARK: - NGLMapViewDelegate
21
extension CustomPuckViewController: NGLMapViewDelegate {
22
23
/**
24
Asks the user styling options for each default user location annotation view.
25
26
This method is called many times during gesturing, so you should avoid performing
27
complex or performance-intensive tasks in your implementation.
28
29
@param mapView The map view that is tracking the user's location.
30
*/
31
func mapView(styleForDefaultUserLocationAnnotationView mapView: NGLMapView) -> NGLUserLocationAnnotationViewStyle {
32
let locationStyle = NGLUserLocationAnnotationViewStyle()
33
/**
34
The fill color for the puck view.
35
*/
36
locationStyle.puckFillColor = UIColor.blue
37
/**
38
The shadow color for the puck view.
39
*/
40
locationStyle.puckShadowColor = UIColor.red
41
/**
42
The shadow opacity for the puck view.
43
Set any value between 0.0 and 1.0.
44
The default value of this property is equal to `0.25`
45
*/
46
locationStyle.puckShadowOpacity = 0.25
47
/**
48
The fill color for the arrow puck.
49
*/
50
locationStyle.puckArrowFillColor = UIColor.black
51
/**
52
The fill color for the puck view.
53
*/
54
locationStyle.haloFillColor = UIColor.white
55
56
if #available(iOS 14, *) {
57
/**
58
The halo fill color for the approximate view.
59
*/
60
locationStyle.approximateHaloFillColor = UIColor.white
61
/**
62
The halo border color for the approximate view.
63
*/
64
locationStyle.approximateHaloBorderColor = UIColor.white
65
/**
66
The halo border width for the approximate view.
67
The default value of this property is equal to `2.0`
68
*/
69
locationStyle.approximateHaloBorderWidth = 2.0
70
/**
71
The halo opacity for the approximate view.
72
Set any value between 0.0 and 1.0
73
The default value of this property is equal to `0.15`
74
*/
75
locationStyle.approximateHaloOpacity = 0.15
76
}
77
78
return locationStyle
79
}
80
81
/**
82
Returns a view object to mark the given point annotation object on the map.
83
Implement this method to mark a point annotation with a view object. If you
84
want to mark a particular point annotation with a static image instead, omit
85
this method or have it return `nil` for that annotation, then implement
86
`-mapView:imageForAnnotation:` instead.
87
Annotation views are compatible with UIKit, Core Animation, and other Cocoa
88
Touch frameworks. On the other hand, static annotation images use less memory
89
and draw more quickly than annotation views.
90
The user location annotation view can also be customized via this method. When
91
`annotation` is an instance of `NGLUserLocation` (or equal to the map view's
92
`userLocation` property), return an instance of `NGLUserLocationAnnotationView`
93
(or a subclass thereof).
94
@param mapView The map view that requested the annotation view.
95
@param annotation The object representing the annotation that is about to be
96
displayed.
97
@return The view object to display for the given annotation or `nil` if you
98
want to display an annotation image instead.
99
*/
100
func mapView(_ mapView: NGLMapView, viewFor annotation: NGLAnnotation) -> NGLAnnotationView? {
101
let annotationView = CustomUserLocationAnnotationView(frame: CGRect.zero)
102
annotationView.frame = CGRect(x:0, y:0, width:annotationView.intrinsicContentSize.width, height:annotationView.intrinsicContentSize.height);
103
return annotationView
104
}
105
106
}

Location tracking mode

This subsection focuses on different location tracking modes available in the iOS Maps SDK. It explains the concept of location tracking modes, such as follow, follow with course, and follow with heading. Developers can understand how each tracking mode works and choose the appropriate one based on their application's needs. These modes enable the map to dynamically adjust and center on the user's location as they move, providing a smooth and intuitive user experience.

The provided code example demonstrates how to show the user's location on a map and change the tracking mode using the iOS Maps SDK.

1
import UIKit
2
import Nbmap
3
enum LocationType {
4
case HidePuckView
5
case UpdateToFollow
6
case UpdateToFollowWithHeading
7
case UpdateToFollowWithCourse
8
case GetUserLocation
9
}
10
class LocationStyleViewController: UIViewController {
11
var nbMapView: NGLMapView! {
12
didSet {
13
oldValue?.removeFromSuperview()
14
if let mapView = nbMapView {
15
view.insertSubview(mapView, at: 0)
16
}
17
}
18
}
19
20
var button: UIButton!
21
22
let typeList = [
23
LocationType.HidePuckView,
24
LocationType.UpdateToFollow,
25
LocationType.UpdateToFollowWithCourse,
26
LocationType.UpdateToFollowWithHeading,
27
LocationType.GetUserLocation
28
]
29
30
override func viewDidLoad() {
31
super.viewDidLoad()
32
nbMapView = NGLMapView(frame:self.view.bounds)
33
nbMapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
34
nbMapView.delegate = self
35
36
button = UIButton(type: .system)
37
button.setTitle("Settings", for: .normal)
38
button.addTarget(self, action: #selector(showSetings), for: .touchUpInside)
39
button.frame = CGRect(x: 0, y: 0, width: 100, height: 40)
40
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: button)
41
}
42
43
@objc func showSetings() {
44
let tableViewController = UITableViewController(style: .plain)
45
tableViewController.tableView.delegate = self
46
tableViewController.tableView.dataSource = self
47
tableViewController.title = "Locations Settings"
48
self.present(tableViewController, animated: true)
49
}
50
51
func performeSettings(tyle: LocationType) {
52
switch tyle {
53
case LocationType.UpdateToFollow:
54
nbMapView.setUserTrackingMode(.follow,animated: true,completionHandler: nil)
55
break
56
case LocationType.UpdateToFollowWithCourse:
57
nbMapView.setUserTrackingMode(.followWithCourse,animated: true,completionHandler: nil)
58
break
59
case LocationType.UpdateToFollowWithHeading:
60
nbMapView.setUserTrackingMode(.followWithHeading,animated: true,completionHandler: nil)
61
break
62
case LocationType.HidePuckView:
63
nbMapView.setUserTrackingMode(.none,animated: true,completionHandler: nil)
64
break
65
case LocationType.GetUserLocation:
66
if let userLocation = nbMapView.userLocation {
67
let location = userLocation.location
68
let isUpdating = userLocation.isUpdating
69
let title = userLocation.title
70
let subtitle = userLocation.subtitle ?? ""
71
print("location:" + location!.description)
72
print("isUpdating:" + String(isUpdating))
73
print("title:" + title)
74
print("subtitle:" + subtitle)
75
if let heading = userLocation.heading {
76
print(heading.description)
77
}
78
}
79
break
80
}
81
82
}
83
}
84
extension LocationStyleViewController: NGLMapViewDelegate {
85
func mapView(_ mapView: NGLMapView, didFinishLoading style: NGLStyle){
86
87
let camera = NGLMapCamera(lookingAtCenter: CLLocationCoordinate2DMake(12.94798778, 77.57375084),
88
acrossDistance:10000,
89
pitch:0,
90
heading:0)
91
nbMapView.fly(to: camera)
92
93
}
94
95
/**
96
Tells the user that the map view will begin tracking the user's location.
97
This method is called when the value of the `showsUserLocation` property
98
changes to `YES`.
99
@param mapView The map view that is tracking the user's location.
100
*/
101
func mapViewWillStartLocatingUser(_ mapView: NGLMapView) {
102
103
}
104
105
/**
106
Tells the user that the map view has stopped tracking the user's location.
107
This method is called when the value of the `showsUserLocation` property
108
changes to `NO`.
109
@param mapView The map view that is tracking the user's location.
110
*/
111
func mapViewDidStopLocatingUser(_ mapView: NGLMapView) {
112
113
}
114
115
116
/**
117
Asks the user styling options for each default user location annotation view.
118
119
This method is called many times during gesturing, so you should avoid performing
120
complex or performance-intensive tasks in your implementation.
121
122
@param mapView The map view that is tracking the user's location.
123
*/
124
func mapView(styleForDefaultUserLocationAnnotationView mapView: NGLMapView) -> NGLUserLocationAnnotationViewStyle {
125
let locationStyle = NGLUserLocationAnnotationViewStyle()
126
/**
127
The fill color for the puck view.
128
*/
129
locationStyle.puckFillColor = UIColor.blue
130
/**
131
The shadow color for the puck view.
132
*/
133
locationStyle.puckShadowColor = UIColor.red
134
/**
135
The shadow opacity for the puck view.
136
Set any value between 0.0 and 1.0.
137
The default value of this property is equal to `0.25`
138
*/
139
locationStyle.puckShadowOpacity = 0.25
140
/**
141
The fill color for the arrow puck.
142
*/
143
locationStyle.puckArrowFillColor = UIColor.black
144
/**
145
The fill color for the puck view.
146
*/
147
locationStyle.haloFillColor = UIColor.white
148
149
if #available(iOS 14, *) {
150
/**
151
The halo fill color for the approximate view.
152
*/
153
locationStyle.approximateHaloFillColor = UIColor.white
154
/**
155
The halo border color for the approximate view.
156
*/
157
locationStyle.approximateHaloBorderColor = UIColor.white
158
/**
159
The halo border width for the approximate view.
160
The default value of this property is equal to `2.0`
161
*/
162
locationStyle.approximateHaloBorderWidth = 2.0
163
/**
164
The halo opacity for the approximate view.
165
Set any value between 0.0 and 1.0
166
The default value of this property is equal to `0.15`
167
*/
168
locationStyle.approximateHaloOpacity = 0.15
169
}
170
171
return locationStyle
172
}
173
174
/**
175
Tells the user that the location of the user was updated.
176
While the `showsUserLocation` property is set to `YES`, this method is called
177
whenever a new location update is received by the map view. This method is also
178
called if the map view's user tracking mode is set to
179
`NGLUserTrackingModeFollowWithHeading` and the heading changes, or if it is set
180
to `NGLUserTrackingModeFollowWithCourse` and the course changes.
181
This method is not called if the application is currently running in the
182
background. If you want to receive location updates while running in the
183
background, you must use the Core Location framework.
184
private @param mapView The map view that is tracking the user's location.
185
@param userLocation The location object represents the user's latest
186
location. This property may be `nil`.
187
*/
188
func mapView(_ mapView: NGLMapView, didUpdate userLocation: NGLUserLocation?) {
189
190
}
191
192
/**
193
Tells the user that an attempt to locate the user's position failed.
194
@param mapView The map view that is tracking the user's location.
195
@param error An error object containing the reason why location tracking
196
failed.
197
*/
198
func mapView(_ mapView: NGLMapView, didFailToLocateUserWithError error: Error) {
199
200
}
201
202
203
/**
204
Tells the user that the map view's user tracking mode has changed.
205
This method is called after the map view asynchronously changes to reflect the
206
new user tracking mode, for example by beginning to zoom or rotate.
207
private @param mapView The map view changed its tracking mode.
208
@param mode The new tracking mode.
209
@param animated Whether the change caused an animated effect on the map.
210
*/
211
func mapView(_ mapView: NGLMapView, didChange mode: NGLUserTrackingMode, animated: Bool ) {
212
213
}
214
215
/**
216
Returns a screen coordinate at which to position the user location annotation.
217
This coordinate is relative to the map view's origin after applying the map view's
218
content insets.
219
When unimplemented, the user location annotation is aligned within the center of
220
the map view with respect to the content insets.
221
This method will override any values set by `NGLMapView.userLocationVerticalAlignment`
222
or `-[NGLMapView setUserLocationVerticalAlignment:animated:]`.
223
@param mapView The map view that is tracking the user's location.
224
225
Notes: We don't need to set the anchor point for now, so comment out this method first
226
*/
227
// func mapViewUserLocationAnchorPoint(_ mapView: NGLMapView ) -> CGPoint {
228
//
229
// }
230
/**
231
Tells the user that the map's location updates accuracy authorization has changed.
232
233
This method is called after the user changes location accuracy authorization when
234
requesting location permissions or in privacy settings.
235
236
@param mapView The map view that changed its location accuracy authorization.
237
@param manager The location manager reporting the update.
238
239
*/
240
func mapView(_ apView: NGLMapView, didChangeLocationManagerAuthorization manager: NGLLocationManager) {
241
242
}
243
244
/**
245
Returns a view object to mark the given point annotation object on the map.
246
Implement this method to mark a point annotation with a view object. If you
247
want to mark a particular point annotation with a static image instead, omit
248
this method or have it return `nil` for that annotation, then implement
249
`-mapView:imageForAnnotation:` instead.
250
Annotation views are compatible with UIKit, Core Animation, and other Cocoa
251
Touch frameworks. On the other hand, static annotation images use less memory
252
and draw more quickly than annotation views.
253
The user location annotation view can also be customized via this method. When
254
`annotation` is an instance of `NGLUserLocation` (or equal to the map view's
255
`userLocation` property), return an instance of `NGLUserLocationAnnotationView`
256
(or a subclass thereof).
257
@param mapView The map view that requested the annotation view.
258
@param annotation The object representing the annotation that is about to be
259
displayed.
260
@return The view object to display for the given annotation or `nil` if you
261
want to display an annotation image instead.
262
*/
263
func mapView(_ mapView: NGLMapView, viewFor annotation: NGLAnnotation) -> NGLAnnotationView? {
264
return nil
265
}
266
267
}
268
extension LocationStyleViewController: UITableViewDelegate, UITableViewDataSource {
269
270
func settingsTitlesForRaw(index: Int) -> String {
271
let type = typeList[index]
272
var title: String = ""
273
switch type {
274
case LocationType.HidePuckView :
275
title = "Hide puck view"
276
break
277
case LocationType.UpdateToFollowWithHeading:
278
title = "Update puck view to follow with heading"
279
break
280
case LocationType.UpdateToFollowWithCourse:
281
title = "Update puck view to follow with course"
282
break
283
case LocationType.UpdateToFollow:
284
title = "Update puck view to follow"
285
break
286
case LocationType.GetUserLocation:
287
title = "Get user location"
288
break
289
}
290
return title
291
}
292
293
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
294
return typeList.count
295
}
296
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
297
let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
298
cell.textLabel?.text = settingsTitlesForRaw(index: indexPath.row)
299
return cell
300
}
301
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
302
tableView.isHidden = true
303
let type = typeList[indexPath.row]
304
dismissSettings(type: type)
305
}
306
307
func dismissSettings(type: LocationType) {
308
dismiss(animated: true)
309
performeSettings(tyle: type)
310
}
311
}
docs-imagedocs-image

Let's break down the code:

The code begins with the import statements for the required frameworks, UIKit and Nbmap.

Enum Declaration:

  • The LocationType enum defines different types of location settings, such as hiding the puck view, updating to follow the user's location, updating to follow with a heading, updating to follow with a course, and getting the user's location.

Class Declaration:

  • The LocationStyleViewController class is a subclass of UIViewController and serves as the main view controller for the location functionality.

  • It declares a property nbMapView of type NGLMapView to display the map view and handles its setup and removal.

  • It also declares a property button of type UIButton to show a settings button on the navigation bar.

  • The class includes an array typeList that stores the different LocationType options.

  • The viewDidLoad() method initializes the nbMapView and sets its delegate. It also sets up the settings button on the navigation bar.

  • The showSettings() method is called when the settings button is tapped. It presents a table view controller to display location settings options.

  • The performSettings(type:) method is called when a location setting is selected. It performs the corresponding action based on the selected LocationType.

Extensions:

  • The LocationStyleViewController extension implements the NGLMapViewDelegate protocol, providing necessary delegate methods for the map view.

  • The mapView(_:didFinishLoading:) method is called when the map finishes loading. It sets the initial camera position.

  • Other delegate methods, such as mapViewWillStartLocatingUser, mapViewDidStopLocatingUser, and mapView(_:didChange:animated:), are implemented but are currently empty. They can be used to handle various events related to user location tracking.

  • The mapView(styleForDefaultUserLocationAnnotationView:) method customizes the appearance of the user location annotation view by setting properties such as puckFillColor, puckShadowColor, and haloFillColor.

  • The mapView(_:didUpdate:) method is called when the user's location is updated. Currently, it is empty and can be used to perform actions based on the user's updated location.

  • Other delegate methods, such as mapView(_:didFailToLocateUserWithError:) and mapView(_:didChangeLocationManagerAuthorization:), are implemented but are currently empty.

Additional Extensions:

  • The LocationStyleViewController extension implements the UITableViewDelegate and UITableViewDataSource protocols to handle the settings table view.

  • The methods in these extensions populate the table view with the available location settings options and handle selection.

  • The dismissSettings(type:) method is called when a location setting is selected, and it dismisses the settings view controller and performs the corresponding action.

Overall, the code example provides a view controller that displays a map view, handles user location tracking, and allows the user to change the location tracking mode based on different settings.

ยฉ 2024 NextBillion.ai all rights reserved.