I'm following an online tutorial to make a simple project that displays a user's location on the map. However, when I run it, the user location is not displayed and there is no pop up to ask for location permission. I'm not sure how I can fix that. I've attached the code below.
import MapKit
import SwiftUI
struct ContentView: View {
#StateObject private var viewModel=ContentViewModel()
var body: some View {
Map(coordinateRegion: $viewModel.region)
.ignoresSafeArea()
.onAppear{viewModel.checkIfLocationServicesIsEnabled()}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
final class ContentViewModel: NSObject, ObservableObject, CLLocationManagerDelegate{
#Published var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude:37.3331516, longitude: -121.891054), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1));
var locationManager: CLLocationManager?
func checkIfLocationServicesIsEnabled(){
if CLLocationManager.locationServicesEnabled(){
locationManager=CLLocationManager()
locationManager!.delegate=self
}
else{
print("Turn location on")
}
}
private func checkLocationAuthorization(){
guard let locationManager = locationManager else {
return
}
switch locationManager.authorizationStatus{
case.notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
print("Your location is restricted likely due to parental controls.")
case .denied:
print("You have denied this app location permission. Go into settings to change it.")
case .authorizedAlways:
region=MKCoordinateRegion(center: locationManager.location!.coordinate, span:MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
case .authorizedWhenInUse:
region=MKCoordinateRegion(center: locationManager.location!.coordinate, span:MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
#unknown default:
break
}
func locationManagerDidChangeAuthorization(_manager: CLLocationManager) {
checkLocationAuthorization()
}
}
}
Your code has 2 issues
You are not asking for permissions.
You implemented the delegate wrong.
This should work:
final class ContentViewModel: NSObject, ObservableObject, CLLocationManagerDelegate{
#Published var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude:37.3331516, longitude: -121.891054), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1));
var locationManager: CLLocationManager?
func checkIfLocationServicesIsEnabled(){
if CLLocationManager.locationServicesEnabled(){
locationManager=CLLocationManager()
locationManager?.delegate=self
//ask for permissions here
//depending on your usage you could also ask for
//locationManager?.requestWhenInUseAuthorization()
locationManager?.requestAlwaysAuthorization()
}
else{
print("Turn location on")
}
}
private func checkLocationAuthorization(){
guard let locationManager = locationManager else {
return
}
switch locationManager.authorizationStatus{
case.notDetermined:
//the function containing this will only be called if the permission get requested so remove it
//locationManager.requestWhenInUseAuthorization()
case .restricted:
print("Your location is restricted likely due to parental controls.")
case .denied:
print("You have denied this app location permission. Go into settings to change it.")
case .authorizedAlways:
region=MKCoordinateRegion(center: locationManager.location!.coordinate, span:MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
case .authorizedWhenInUse:
region=MKCoordinateRegion(center: locationManager.location!.coordinate, span:MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1))
#unknown default:
break
}
}
// this function was wrapped inside your checkLocationAuthorization() function
//move it to outer scope. It gets called every time you request permissions
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
checkLocationAuthorization()
}
}
Be aware you will have to add multiple privacy keys to get this working.
Related
In my project, I'm fetching the data about the houses/buildings and along with other details, I show how far it is from the user. I'm only a beginner, so I will try to be as much explicit as possible.
My issue is that I don't know where to put the function that calculates the distance in KM and how to call it properly in the MVVM project. See I have a ViewModel file that includes ViewModel class responsible for Networking and a LocationManager class
responsible for tracking user location. The latitude and longitude come from the ViewModel from API and I believe the distance calculation should be made in LocationManager. I'm not sure how can I "connect" these two classes.
My main goals are:
Figure out where to put the func to calculate the distance. User coords are accessible from the LocationManager and house coords are accessible from the API. I would like to know if there's a way to merge these two classes to use the data in one func.
Understand if the distanceInKM method is correct. Despite it doesn't throw, it still displays a placeholder value.
As the minimum reproducible project, here's the code:
ContentView:
struct ContentView: View {
#ObservedObject var viewModel = ViewModel()
#StateObject var locationManager = LocationManager()
var body: some View {
VStack {
HouseListView(housesVM: viewModel)
}
.onAppear {
viewModel.fetchHouses()
}
}
}
HouseListView(A view that's called in ContentView:
struct HouseListView: View {
#ObservedObject var housesVM: ViewModel
#StateObject var locationManager = LocationManager()
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(alignment: .leading) {
ForEach(housesVM.info, id: \.id) { house in
GetHouseCellView(
distance: Double(locationManager.distanceInKM(latitude: house.latitude, longitude: house.longitude)) ?? 0.00, //Here's the place where function is called
bedrooms: house.bedrooms)
}
}
}
}
private func GetHouseCellView(distance: Double, bedrooms: Int) -> some View {
HStack(spacing: 20) {
Label("\(bedrooms)", image: "bed-2")
Label("\(distance) km", image: "pin") //Here the final distance should be displayed, i.e 36,4 km
}
}
Quite basic ViewModel:
class ViewModel: ObservableObject {
#Published var info: [Houses] = []
func fetchHouses() {
//URL & URLRequest here
let dataTask = URLSession.shared.dataTask(with: request) { data, response, error in
let decoder = JSONDecoder()
do {
if let data = data {
let result = try decoder.decode([Houses].self, from: data)
DispatchQueue.main.async {
self.info = result
}
}
} catch {
print("whoopsie! There's an error: \(error.localizedDescription)")
}
}
dataTask.resume()
}
}
}
And a LocationManager:
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
#Published var locationStatus: CLAuthorizationStatus?
#Published var lastLocation: CLLocation?
override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
var statusString: String {
guard let status = locationStatus else {
return "unknown"
}
switch status {
case .notDetermined: return "notDetermined"
case .authorizedWhenInUse: return "authorizedWhenInUse"
case .authorizedAlways: return "authorizedAlways"
case .restricted: return "restricted"
case .denied: return "denied"
default: return "unknown"
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
locationStatus = status
print(#function, statusString)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
lastLocation = location
print(#function, location)
}
func distanceInKM(latitude: Int, longitude: Int) -> Double { //Here's the method I made to calculate an actual distance
let houseCoordinates = CLLocation(latitude: CLLocationDegrees(latitude), longitude: CLLocationDegrees(longitude))
let userCoordinates = CLLocation(latitude: lastLocation?.coordinate.latitude ?? 50, longitude: lastLocation?.coordinate.longitude ?? 30)
let distance = userCoordinates.distance(from: houseCoordinates) / 1000 //.distance comes in meters so /1000 is to have a KM value
let s = String(format: "%.0f", distance)
return Double(s + "Km") ?? 35.5 // This value of 35.5 as placeholder is constantly displayed instead of the actual value
}
}
This func logic was taken from this post
Simple type error :
Double(s + "Km")
will always return nil as s + "Km" is not a valid double.
Just Return :
Double(distance)
If you want to return a String change the type of the method and return
s + "km"
EDIT :
If you want to display distance in km : in GetHouseCellView change distance label to :
Label(String(format: "%.2f km", distance), image: "pin")
It is better to format the distance Double when you use it.
I'm pretty new to coding in general and to get to this point I've been following multiple tutorials online which may have caused my code to be jumbled so I apologise for this.
I have started creating an app using MapKit with map annotations in my home town. I am currently living abroad so my location is not where these map annotations are. When I accept the location permissions the map defaults to the first annotation pin where I would like it to default to my current location.
My code is below and any help/explanation would be greatly appreciated.
Locations View Model
'''class LocationsViewModel: ObservableObject {
#Published var locations: [Location]
#Published var mapLocation: Location {
didSet {
updateMapRegion(location: mapLocation)
}
}
#Published var mapRegion: MKCoordinateRegion = MKCoordinateRegion()
let mapSpan = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
init() {
let locations = LocationsDataServices.locations
self.locations = locations
self.mapLocation = locations.first!
self.updateMapRegion(location: locations.first!)
}
private func updateMapRegion(location: Location) {
withAnimation(.easeInOut) {
mapRegion = MKCoordinateRegion(
center: location.coordinates,
span: mapSpan)
}
}
func showNextLocation(location: Location) {
withAnimation(.easeInOut) {
mapLocation = location
}
}
}'''
Locations Services Model
'''import MapKit
enum MapDetails {
static let startingLocation = CLLocationCoordinate2D(latitude: ***, longitude: ***)
static let defaultSpan = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
}
final class LocationServicesModel: NSObject, ObservableObject, CLLocationManagerDelegate {
#Published var region = MKCoordinateRegion(center: MapDetails.startingLocation, span: MapDetails.defaultSpan)
var locationManager: CLLocationManager?
func checkIfLocationServicesIsEnabled() {
if CLLocationManager.locationServicesEnabled() {
locationManager = CLLocationManager()
locationManager!.delegate = self
locationManager?.desiredAccuracy = kCLLocationAccuracyBest
} else {
print("turn on location manager")
}
}
private func checkLocationAuthorisation() {
guard let locationManager = locationManager else { return }
switch locationManager.authorizationStatus {
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
print("location is restricted")
case .denied:
print("location has been denied, go into settings to change permission")
case .authorizedAlways, .authorizedWhenInUse:
break
#unknown default:
break
}
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
checkLocationAuthorisation()
}'''
The code works to a degree, the map annotations are placed correctly and it does show my current location but I'm not sure where or how I'd get the map to centre of the user location on acceptance of location permissions instead of the coordinates I have input above.
Thanks!
Once you have the required permission you need to invoke startUpdatingLocation()
locationManager.startUpdatingLocation()
This starts the generation of updates that report the user’s current location. These updates are available to you via the delegate method:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// Ensure we have an actual location in the update.
guard let location = locations.last else { return }
// Do something with the location.
}
The location is a CLLocation and you can extract the coordinate from that.
let span = MKCoordinateSpan(latitudeDelta: 0.009, longitudeDelta: 0.009)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.setRegion(region, animated: true)
Good afternoon,
I am having trouble displaying a map where it only centers around the user and will stay on the user with movement. My error is in my view file where I mark //HERE.
My error is Type '()' cannot conform to 'View'
Why is it that this line is giving me an error? If that line runs, my assumption would be that the map region is changing but it still would return the Map which conforms. View file is presented below.
If I run it without the commented line, it does not display my current location. I have my simulator settings are set to Features > Location > Apple. Even when I am zooming way out, nothing is marked on the map.
import SwiftUI
import MapKit
struct Location: Identifiable {
let id = UUID()
let name: String
let content: String?
let lat: Double
let lon: Double
var dangerLevel: CGFloat? = 10.0
var coord: CLLocationCoordinate2D { CLLocationCoordinate2D(latitude: lat, longitude: lon) }
}
struct ContentView: View {
#EnvironmentObject var locationManager: LocationManager
#State private var userTrackingMode: MapUserTrackingMode = .follow
#State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 40.7128, longitude: 74.0060), span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03))
var body: some View {
var locationManager = LocationManager()
region = MKCoordinateRegion(center: locationManager.location!.coordinate, span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03)) // HERE!!!!
VStack {
Map(coordinateRegion: $region,
interactionModes: .all,
showsUserLocation: true)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(LocationManager())
}
}
This is the next file where I define my locationManager
import Foundation
import CoreLocation
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
#Published var location: CLLocation?
override init() {
super.init()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
}
}
extension LocationManager : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
self.location = location
}
}
There were a couple of issues with your code. First, to answer the question asked, you should refrain from putting variables that are NOT views directly into the var body. While there are ways of getting around this restriction, there is not good reason to any longer. Since region is not a view, the code through the error. And yes, I know you defined var locationManager and the ViewBuilder took it as it was the init of a variable, not the variable itself. However, you already ha a reference to locationManager that you defined in the header. Use that.
I put a few more changes into your code with comments to help things along. Let me know if you have further questions.
struct ContentView: View {
// Unless you are using locationManager all over your code, you don't need to pass it as an
// .environmentObject, though you can if needed. Since this is the first instance in this example
// of locationManager, I made it a #StateObject.
#StateObject var locationManager = LocationManager()
#State private var userTrackingMode: MapUserTrackingMode = .follow
#State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 37.60697453, longitude: -122.42798519), span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03))
var body: some View {
VStack {
Map(coordinateRegion: $region,
interactionModes: .all,
showsUserLocation: true)
// Since locationManager is an ObservableObject, you can watch for changes with .onChange(of:)
.onChange(of: locationManager.location) { newLocation in
// Never force unwrap an optional unless you just set it yourself in the code.
guard let newLocation = newLocation else { return }
region = MKCoordinateRegion(center: newLocation.coordinate, span: MKCoordinateSpan( latitudeDelta: 0.03, longitudeDelta: 0.03)) // HERE!!!!
}
}
}
}
import CoreLocation
// I would consider renaming this class. It can be confusing to see
// locationManager.locationManager in code.
class LocationManager: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
#Published var location: CLLocation?
override init() {
super.init()
// You can generally drop .self, with some exceptions. The compiler will correct you.
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
}
extension LocationManager : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
// This is an exception to dropping self when a variable in a closure has the same name as a
// self variable.
self.location = location
}
}
I want to allow users to zoom in/out and move freely around the map while the app is tracking and displaying their current location. Later i will try to add a button that you can press and it will move you back to the center of user location. I think the problem is that in my LocationManager file i am creating new region everytime i get a new location coordinates. But i do not know any other ways of tracking user location and displaying it.
LocationManager:
import Foundation
import CoreLocation
import MapKit
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate{
let locationManager = CLLocationManager()
#Published var location: CLLocationCoordinate2D?
#Published var region = MKCoordinateRegion()
override init(){
super.init()
locationManager.delegate = self
}
func startTracking() {
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
}
func stopTracking() {
print("stop test")
locationManager.stopUpdatingLocation()
locationManager.allowsBackgroundLocationUpdates = false
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let tempLocation = locations.last?.coordinate
print(tempLocation)
let center = CLLocationCoordinate2D(latitude: tempLocation?.latitude ?? 0.0, longitude: tempLocation?.longitude ?? 0.0)
let span = MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
let tempRegion = MKCoordinateRegion(center: center, span: span)
DispatchQueue.main.async {
self.location = tempLocation
self.region = tempRegion
}
}
}
ContentView:
import SwiftUI
import MapKit
struct ContentView: View {
#State var isButtonPressed: Bool = false
#StateObject var locationManager = LocationManager()
var body: some View {
VStack{
Button("START"){
isButtonPressed = true
locationManager.startTracking()
}
Button("STOP"){
isButtonPressed = false
locationManager.stopTracking()
}
mapView(isButtonPressed: isButtonPressed, manager: locationManager)
}
}
}
struct mapView: View{
var isButtonPressed: Bool
#ObservedObject var manager: LocationManager
#State var defaultRegion = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 0, longitude: 0), latitudinalMeters: 1000, longitudinalMeters: 1000)
var body: some View{
if isButtonPressed == true{
if let location = manager.location {
Map(coordinateRegion: $manager.region, interactionModes: .all, showsUserLocation: true, userTrackingMode:nil)
} else{
Map(coordinateRegion: $defaultRegion)
}
}
else
{
Map(coordinateRegion: $defaultRegion)
}
}
}
Thanks!
Creating a series of regions is the wrong way to monitor the user's location.
It's been quite a while since I've written a mapping app, but here's the general idea of what you should do:
Create an instance of the location manager.
Set yourself as the location manager's delegate.
Ask the user for permission to get location updates while your app is running (if you don't have permission already.)
Call startUpdatingLocation() to request location updates
Respond to calls to the location manager delegate's locationManager(_:didUpdateLocations:) method as needed. (If you set up the map to show the user's location you won't have to do anything special - the blue dot will update automatically.)
I am trying to load a map and have the initial location on user's location as well as showing the user's location on the map using SwiftUI. I don't know how to do that in SwiftUI.
I have tried to put 'view.showsUserLocation = true' in updateUIView function but it is not working.
import SwiftUI
import MapKit
struct MapView : UIViewRepresentable {
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
view.showsUserLocation = true
let coordinate = CLLocationCoordinate2D(
latitude: 34.011286, longitude: -116.166868)
let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
let region = MKCoordinateRegion(center: view.userLocation.location?.coordinate ?? coordinate, span: span)
view.setRegion(region, animated: true)
}
}
The location comes nil when I tried to print it.
Add key Privacy - Location When In Use Usage Description and description in Info.plist
Then try with updating below function:
func updateUIView(_ view: MKMapView, context: Context) {
view.showsUserLocation = true
// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
// self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
self.locationManager.startUpdatingLocation()
//Temporary fix: App crashes as it may execute before getting users current location
//Try to run on device without DispatchQueue
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
let locValue:CLLocationCoordinate2D = self.locationManager.location!.coordinate
print("CURRENT LOCATION = \(locValue.latitude) \(locValue.longitude)")
let coordinate = CLLocationCoordinate2D(
latitude: locValue.latitude, longitude: locValue.longitude)
let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
let region = MKCoordinateRegion(center: coordinate, span: span)
view.setRegion(region, animated: true)
})
}
}
This is the cleanest way I have found to setup CoreLocation and MapView. First, you have to create an UIViewRepresentable to use CoreLocation in SwiftUI.
Do not forget to enable in your Info.plist file this Privacy with a message:
Privacy - Location Always and When In Use Usage Description
Privacy - Location When In Use Usage Description
Privacy - Location Always Usage Description
import SwiftUI
import MapKit
// MARK: Struct that handle the map
struct MapView: UIViewRepresentable {
#Binding var locationManager: CLLocationManager
#Binding var showMapAlert: Bool
let map = MKMapView()
///Creating map view at startup
func makeUIView(context: Context) -> MKMapView {
locationManager.delegate = context.coordinator
return map
}
func updateUIView(_ view: MKMapView, context: Context) {
map.showsUserLocation = true
map.userTrackingMode = .follow
}
///Use class Coordinator method
func makeCoordinator() -> MapView.Coordinator {
return Coordinator(mapView: self)
}
//MARK: - Core Location manager delegate
class Coordinator: NSObject, CLLocationManagerDelegate {
var mapView: MapView
init(mapView: MapView) {
self.mapView = mapView
}
///Switch between user location status
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .restricted:
break
case .denied:
mapView.showMapAlert.toggle()
return
case .notDetermined:
mapView.locationManager.requestWhenInUseAuthorization()
return
case .authorizedWhenInUse:
return
case .authorizedAlways:
mapView.locationManager.allowsBackgroundLocationUpdates = true
mapView.locationManager.pausesLocationUpdatesAutomatically = false
return
#unknown default:
break
}
mapView.locationManager.startUpdatingLocation()
}
}
}
}
This is the way I use it in my SwiftUI view. An alert is toggle in case the permission is denied in the Coordinator class switch:
import SwiftUI
import CoreLocation
// MARK: View that shows map to users
struct HomeView: View {
#State var locationManager = CLLocationManager()
#State var showMapAlert = false
var body: some View {
MapView(locationManager: $locationManager, showMapAlert: $showMapAlert)
.alert(isPresented: $showMapAlert) {
Alert(title: Text("Location access denied"),
message: Text("Your location is needed"),
primaryButton: .cancel(),
secondaryButton: .default(Text("Settings"),
action: { self.goToDeviceSettings() }))
}
}
}
extension HomeView {
///Path to device settings if location is disabled
func goToDeviceSettings() {
guard let url = URL.init(string: UIApplication.openSettingsURLString) else { return }
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
The above codes will cause the app crash because of the inappropriate permission request. Use the below code for better performance and on-time permission.
struct MapView: UIViewRepresentable {
let locationManager = CLLocationManager()
func makeUIView(context: Context) -> MKMapView {
MKMapView(frame: .zero)
}
func updateUIView(_ view: MKMapView, context: Context) {
view.showsUserLocation = true
let status = CLLocationManager.authorizationStatus()
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
if status == .authorizedAlways || status == .authorizedWhenInUse {
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
let location: CLLocationCoordinate2D = locationManager.location!.coordinate
let span = MKCoordinateSpan(latitudeDelta: 0.009, longitudeDelta: 0.009)
let region = MKCoordinateRegion(center: location, span: span)
view.setRegion(region, animated: true)
}
}
}
try this one:
struct OriginMap : UIViewRepresentable {
func makeUIView(context: UIViewRepresentableContext<OriginMap>) -> MKMapView{
MKMapView()
}
func updateUIView(_ mapView: MKMapView, context: Context) {
let locationManager = CLLocationManager()
mapView.showsUserLocation = true
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
let locValue:CLLocationCoordinate2D = locationManager.location!.coordinate
let coordinate = CLLocationCoordinate2D(
latitude: locValue.latitude, longitude: locValue.longitude)
Datas.currentLocation = coordinate
let span = MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapView.setRegion(region, animated: true)
})
}}
Here is the code for SwiftUI2
import MapKit
import SwiftUI
struct MapView: View {
#State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.4353, longitude: 35.23442), span: MKCoordinateSpan(latitudeDelta: 0.15, longitudeDelta: 0.15))
var body: some View {
Map(coordinateRegion: $region)
}
}
struct MapView_Previews: PreviewProvider {
static var previews: some View {
MapView()
}
}
you can also check this URL for more info about other useful features added to SwiftUI2.
import SwiftUI
import MapKit
struct ContentView: View {
#State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: -23.506403, longitude: -46.1509555),
span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
var body: some View {
Map(coordinateRegion: $region, showsUserLocation: true)
}
}
Available for XCode 12.
import SwiftUI
import MapKit
struct ContentView: View {
#State private var region = MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 37.321127, longitude: -122.047790),
span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
var body: some View {
Map(coordinateRegion: $region)
}
}
Using this you can find users region
Text(Locale.current.localizedString(forRegionCode: Locale.current.regionCode!) ?? "")
.font(.system(size: 30))
.fontWeight(.bold)