Skip to content

Show device location

View on GitHub

Show your current position on the map, as well as switch between different types of auto-pan modes.

Screenshot of show device location sample

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

  1. Create a LocationDisplay object with a location data source.
  2. Use the locationDisplay(_:) map view modifier to set the location display for the map view.
  3. Use the LocationDisplay.AutoPanMode property to change how the map behaves when location updates are received.
  4. 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: The default location data source, SystemLocationDataSource, needs the app to be authorized in order to access the device's location. The app must contain appropriate purpose strings (NSLocationWhenInUseUsageDescription, or NSLocationAlwaysAndWhenInUseUsageDescription keys) along with a brief description of how you use location services in the project's Info tab.

Please read the documentation below for further details.

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 153 // 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  struct ShowDeviceLocationView: View {  /// The error shown in the error alert.  @State private var error: Error?   /// A Boolean value indicating whether the settings button is disabled.  @State private var settingsButtonIsDisabled = true   /// The view model for this sample.  @StateObject private var model = Model()   var body: some View {  MapView(map: model.map)  .locationDisplay(model.locationDisplay)  .task {  guard model.locationDisplay.dataSource.status != .started else {  return  }  do {  try await model.startLocationDataSource()  settingsButtonIsDisabled = false  // Updates the current auto-pan mode if it does not match the  // location display's auto-pan mode.  for await mode in model.locationDisplay.$autoPanMode {  if model.autoPanMode != mode {  model.autoPanMode = mode  }  }  } catch {  // Shows an alert with an error if starting the data source fails.  self.error = error  }  }  .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 in  Label(mode.label, image: mode.imageName)  .imageScale(.large)  }  }  }  .disabled(settingsButtonIsDisabled)  }  }  .errorAlert(presentingError: $error)  } }  private extension ShowDeviceLocationView {  /// The model used to store the geo model and other expensive objects  /// used in this view.  @MainActor  class Model: ObservableObject {  /// A Boolean value indicating whether to show the device location.  @Published var isShowingLocation: Bool {  didSet {  locationDisplay.showsLocation = isShowingLocation  }  }   /// The current auto-pan mode.  @Published var autoPanMode: LocationDisplay.AutoPanMode {  didSet {  locationDisplay.autoPanMode = autoPanMode  }  }   /// A map with a standard imagery basemap style.  let map = Map(basemapStyle: .arcGISImageryStandard)   /// A location display using the system location data source.  let locationDisplay: LocationDisplay   init() {  let locationDisplay = LocationDisplay(dataSource: SystemLocationDataSource())  self.locationDisplay = locationDisplay  self.isShowingLocation = locationDisplay.showsLocation  self.autoPanMode = locationDisplay.autoPanMode  }   /// Starts the location data source.  func startLocationDataSource() async throws {  // Requests location permission if it has not yet been determined.  let locationManager = CLLocationManager()  if locationManager.authorizationStatus == .notDetermined {  locationManager.requestWhenInUseAuthorization()  }  // Starts the location display data source.  try await locationDisplay.dataSource.start()  }   /// Stops the location data source.  func stopLocationDataSource() {  Task {  await locationDisplay.dataSource.stop()  }  }  } }  private extension LocationDisplay.AutoPanMode {  /// A human-readable label for each auto-pan mode.  var label: String {  switch self {  case .off: return "Auto-Pan Off"  case .recenter: return "Recenter"  case .navigation: return "Navigation"  case .compassNavigation: return "Compass Navigation"  @unknown default: return "Unknown"  }  }   /// The image name for each auto-pan mode.  var imageName: String {  switch self {  case .off: return "LocationDisplayOffIcon"  case .recenter: return "LocationDisplayDefaultIcon"  case .navigation: return "LocationDisplayNavigationIcon"  case .compassNavigation: return "LocationDisplayHeadingIcon"  @unknown default: return "LocationDisplayOffIcon"  }  } }  #Preview {  NavigationStack {  ShowDeviceLocationView()  } }

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.