Learn Courses My Dashboard

How to center map to users current location?

Hi all,

I’m using MapKit in SwiftUI to display a map with the current location of the user. I have this code so far, but the problem is that I have to manually specify the region.

So my question is, How can I make the map always center around the current location of the user?

I’m not that experienced yet, so I hope you will have some patience with me

struct ContentView: View {

    var body: some View {
        Home()
    }
}


struct Home: View{

    @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 37.785834, longitude: -122.406417), latitudinalMeters: 1, longitudinalMeters: 1)

    @State var tracking : MapUserTrackingMode = .follow

    @State var manager = CLLocationManager()

    @StateObject var managerDelegate = locationDelegate()

    var body: some View {
        VStack{
//            Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $tracking)
            
            Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $tracking, annotationItems: managerDelegate.pins) { pin in
                MapPin(coordinate: pin.location.coordinate, tint: .red)
                
            }.edgesIgnoringSafeArea(.all)
        }.onAppear{
            manager.delegate = managerDelegate
        }
    }
}

class locationDelegate: NSObject,ObservableObject,CLLocationManagerDelegate{
      
    @Published var pins : [Pin] = []

    // Checking authorization status...
  
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {

        if manager.authorizationStatus == .authorizedWhenInUse{
            print("Authorized")
            manager.startUpdatingLocation()
        } else {
            print("not authorized")
            manager.requestWhenInUseAuthorization()
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        pins.append(Pin(location:locations.last!))
    }
}

// Map pins for update
struct Pin : Identifiable {
    var id = UUID().uuidString
    var location : CLLocation
}

You will need to create a UIViewRepresentable View if you have not already done so in which you set up your MapView.

Chris Ching covers this in his iOSFoundations (SwiftUI) course in Module 6 (CitySights App).

If you were using UIKit, this is a very quick demonstration of how to do it.

@Chris_Parker

Thanks for the reply, I managed to update my code so the map is now always centered around the current location of the user. But I’m not sure my code is optimal, would appreciate it if you could take a quick look at it.

A problem I’m having with the new code is that when the user is moving, meaning if I set the simulator to simulate someone running or driving a car, I’m not able to zoom in or out or move the map at all. It keeps readjusting itself. Any ideas?


import SwiftUI
import MapKit
import CoreLocation


struct ContentView: View {

    var body: some View {
        Home()
    }
}


struct Home: View{
    
    @State var tracking : MapUserTrackingMode = .follow

    @State var manager = CLLocationManager()

    @StateObject var managerDelegate = locationDelegate()

    var body: some View {
        VStack{
            
            Map(coordinateRegion: $managerDelegate.region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $tracking, annotationItems: managerDelegate.pins) { pin in
                MapPin(coordinate: pin.location.coordinate, tint: .red)
                
            }.edgesIgnoringSafeArea(.all)
        }.onAppear{
            manager.delegate = managerDelegate
        }
    }
}

class locationDelegate: NSObject,ObservableObject,CLLocationManagerDelegate{
    @Published var pins : [Pin] = []
    
    // From here and down is new
    @Published var location: CLLocation?
    
    @State var hasSetRegion = false
    
    @Published var region = MKCoordinateRegion(
        center: CLLocationCoordinate2D(latitude: 38.898150, longitude: -77.034340),
        span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1)
    )
    
    
    // Checking authorization status...
  
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {

        if manager.authorizationStatus == .authorizedWhenInUse{
            print("Authorized")
            manager.startUpdatingLocation()
        } else {
            print("not authorized")
            manager.requestWhenInUseAuthorization()
        }
    }

    
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // pins.append(Pin(location:locations.last!))

        // From here and down is new
        if let location = locations.last {
            
            self.location = location

            if hasSetRegion == false{
                region = MKCoordinateRegion(center: location.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.001, longitudeDelta: 0.001))
                hasSetRegion = true
            }
        }
    }
}




// Map pins for update
struct Pin : Identifiable {
    var id = UUID().uuidString
    var location : CLLocation
}