Show your current position on the map, as well as switch between different types of auto-pan modes.
Use case
When using a map within a GIS application, it may be helpful for a user to know their own location within a map, whether that's to aid the user's navigation or to provide an easy mean of identifying/collecting geospatial information at their location.
How to use the sample
Tap the "Location Settings" button to open the settings interface.
Toggle "Show Location" to change the visibility of the location indicator in the map view. It will be asked by the system to provide permission to use the device's location, if the user have not yet used location services in this app.
Change the "Auto-Pan Mode" to choose if and how the SDK will position the map view's viewpoint to keep the location indicator in-frame. A menu will appear with the following options to change the LocationDisplay.AutoPanMode:
Off: Starts the location display with no auto-pan mode set.
Re-Center: Starts the location display with auto-pan mode set to recenter.
Navigation: Starts the location display with auto-pan mode set to navigation.
Compass Navigation: Starts the location display with auto-pan mode set to compassNavigation.
How it works
Create a LocationDisplay object with a location data source.
Use the locationDisplay(_:) map view modifier to set the location display for the map view.
Use the LocationDisplay.AutoPanMode property to change how the map behaves when location updates are received.
Use the start() and stop() methods on the location display's data source as necessary.
Relevant API
LocationDataSource
LocationDisplay
LocationDisplay.AutoPanMode
MapView
MapView.locationDisplay(_:)
Additional information
Location permissions are required for this sample.
Note: As of iOS 8, you are required to request the user's permission to enable location services. You must include either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription along with a brief description of how you use location services in the Info plist of your project.
Tags
compass, GPS, location, map, mobile, navigation
Sample Code
ShowDeviceLocationView.swift
Use dark colors for code blocksCopy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright 2022 Esri//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.import ArcGIS
import CoreLocation
import SwiftUI
structShowDeviceLocationView: View{
/// The view model for this sample.@StateObjectprivatevar model =Model()
var body: someView {
MapView(map: model.map)
.locationDisplay(model.locationDisplay)
.task {
await model.startLocationDataSource()
await model.updateAutoPanMode()
}
.onDisappear {
model.stopLocationDataSource()
}
.toolbar {
ToolbarItem(placement: .bottomBar) {
Menu("Location Settings") {
Toggle("Show Location", isOn: $model.isShowingLocation)
Picker("Auto-Pan Mode", selection: $model.autoPanMode) {
ForEach(LocationDisplay.AutoPanMode.allCases, id: \.self) { mode inLabel(mode.label, image: mode.imageName)
.imageScale(.large)
}
}
}
.disabled(model.areSettingsDisabled)
}
}
.alert(isPresented: $model.isShowingAlert, presentingError: model.error)
}
}
privateextensionShowDeviceLocationView{
/// The view model for this sample.@MainActorclassModel: ObservableObject{
/// A Boolean value indicating whether to show the device location.@Publishedvar isShowingLocation: Bool {
didSet {
locationDisplay.showLocation = isShowingLocation
}
}
/// The current auto-pan mode.@Publishedvar autoPanMode: LocationDisplay.AutoPanMode {
didSet {
locationDisplay.autoPanMode = autoPanMode
}
}
/// A Boolean value indicating whether the settings button is disabled.@Publishedvar areSettingsDisabled =true/// A Boolean value indicating whether to show an alert.@Publishedvar isShowingAlert =false/// The error to display in the alert.var error: Error?
/// A map with a standard imagery basemap style.let map =Map(basemapStyle: .arcGISImageryStandard)
/// A location display using the system location data source.let locationDisplay: LocationDisplayinit() {
let locationDisplay =LocationDisplay(dataSource: SystemLocationDataSource())
self.locationDisplay = locationDisplay
self.isShowingLocation = locationDisplay.showLocation
self.autoPanMode = locationDisplay.autoPanMode
}
/// Starts the location data source.funcstartLocationDataSource()async {
// Requests location permission if it has not yet been determined.let locationManager =CLLocationManager()
if locationManager.authorizationStatus == .notDetermined {
locationManager.requestWhenInUseAuthorization()
}
do {
// Starts the location display data source.tryawait locationDisplay.dataSource.start()
areSettingsDisabled =false } catch {
// Shows an alert with an error if starting the data source fails.self.error = error
isShowingAlert =true }
}
/// Stops the location data source.funcstopLocationDataSource() {
Task {
await locationDisplay.dataSource.stop()
}
}
/// Updates the current auto-pan mode if it does not match the location display's auto-pan mode.funcupdateAutoPanMode()async {
forawait mode in locationDisplay.$autoPanMode {
if autoPanMode != mode {
autoPanMode = mode
}
}
}
}
}
privateextensionLocationDisplay.AutoPanMode{
staticvar allCases: [LocationDisplay.AutoPanMode] { [.off, .recenter, .navigation, .compassNavigation] }
/// A human-readable label for each auto-pan mode.var label: String {
switchself {
case .off: return"Off"case .recenter: return"Recenter"case .navigation: return"Navigation"case .compassNavigation: return"Compass Navigation"@unknowndefault: return"Unknown" }
}
/// The image name for each auto-pan mode.var imageName: String {
switchself {
case .off: return"LocationDisplayOffIcon"case .recenter: return"LocationDisplayDefaultIcon"case .navigation: return"LocationDisplayNavigationIcon"case .compassNavigation: return"LocationDisplayHeadingIcon"@unknowndefault: return"LocationDisplayOffIcon" }
}
}