SwiftUI: Как получить координаты центра MapView и вывести их в Text?
В центре карты есть перекрестие красного цвета, мне необходимо получить координаты где находится это перекрестие и вывести их в Text.
Есть догадки что таким образом
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let currentLocation = mapView.centerCoordinate
print("? Координаты \(currentLocation)")
}
Ответы (2 шт):
Автор решения: VAndrJ
→ Ссылка
Вам просто нужно "пробросить" координаты туда, откуда можно их отрисовать. Судя по проекту, это MapViewModel
Вникать не буду что в нем происходит, для примера добавлен @Published, а там уже адаптируйте под свои нужды:
class MapViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
@Published var center: CLLocationCoordinate2D?
...
// В координаторе добавлен @Binding
class Coordinator: NSObject, MKMapViewDelegate {
@Binding var center: CLLocationCoordinate2D?
init(center: Binding<CLLocationCoordinate2D?>) {
self._center = center
}
...
// Естественно его нужно передать:
func makeCoordinator() -> Coordinator {
return MapView.Coordinator(center: $mapData.center)
}
...
// И использовать:
if let center = mapData.center {
Text("Мои координаты: В: \(center.latitude) L: \(center.longitude)")
}
Результат:
Автор решения: Sherstyuk
→ Ссылка
Выложу полный код проекта, возможно кому-то пригодится
Home.swift
import SwiftUI
import CoreLocation
import MapKit
struct Home: View {
@StateObject var mapData = MapViewModel()
// Location Manager....
@State var locationManager = CLLocationManager()
// Целик
struct Cross: Shape {
func path(in rect: CGRect) -> Path {
return Path { path in
path.move(to: CGPoint(x: rect.midX, y: 0))
path.addLine(to: CGPoint(x: rect.midX, y: rect.maxY))
path.move(to: CGPoint(x: 0, y: rect.midY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.midY))
path.move(to: CGPoint(x: rect.midX, y: rect.midY))
path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: 10, startAngle: Angle(degrees: 0), endAngle: Angle(degrees: 360), clockwise: false)
}
}
}
var body: some View {
ZStack {
// Карта
MapView()
.environmentObject(mapData)
.ignoresSafeArea(.all, edges: .all)
// Целик
Cross().stroke(Color.red)
.frame(width: 90, height: 90)
// Всё что по верх карты
VStack {
VStack(spacing: 0) {
// Панель поиска
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.gray)
TextField("Search", text: $mapData.searchTxt)
.colorScheme(.light)
}
.padding(.vertical,10)
.padding(.horizontal)
.background(Color.white)
// Displaying Results...
if !mapData.places.isEmpty && mapData.searchTxt != "" {
ScrollView {
VStack(spacing: 15) {
ForEach(mapData.places) {place in
Text(place.placemark.name ?? "")
.foregroundColor(.black)
.frame(maxWidth: .infinity,alignment: .leading)
.padding(.leading)
.onTapGesture{
mapData.selectPlace(place: place)
}
Divider()
}
}
.padding(.top)
}
.background(Color.white)
}
} .padding()
Spacer()
// Панель кнопок
VStack {
Button(action: mapData.focusLocation, label: {
Image(systemName: "location.fill")
.font(.title2)
.padding(10)
.background(Color.primary)
.clipShape(Circle())
})
Button(action: mapData.updateMapType, label: {
Image(systemName: mapData.mapType == .standard ? "network" : "map")
.font(.title2)
.padding(10)
.background(Color.primary)
.clipShape(Circle())
})
if let center = mapData.center {
Text ("Мои координаты: В: \(center.latitude) L: \(center.longitude)")
}
}
.frame(maxWidth: .infinity, alignment: .trailing)
.padding()
}
}
.onAppear(perform: {
// Setting Delegate...
locationManager.delegate = mapData
locationManager.requestWhenInUseAuthorization()
})
// Permission Denied Alert...
.alert(isPresented: $mapData.permissionDenied, content: {
Alert(title: Text("Permission Denied"), message: Text("Please Enable Permission In App Settings"), dismissButton: .default(Text("Go Setting"), action: {
// Redireting User To Settings...
UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
}))
})
.onChange(of: mapData.searchTxt, perform: { value in
// Searching Places...
// You can use your own delay time to avoid Continous Search Request...
let delay = 0.3
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
if value == mapData.searchTxt {
// Search...
self.mapData.searchQuery()
}
}
})
}
func regionToString(_ region: MKCoordinateRegion) -> String {
"\(region.center.latitude), \(region.center.longitude)"
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
MapView.swift
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
@EnvironmentObject var mapData: MapViewModel
func makeCoordinator() -> Coordinator {
return MapView.Coordinator(center: $mapData.center)
}
func makeUIView(context: Context) -> MKMapView {
let view = mapData.mapView
view.showsCompass = false
view.showsUserLocation = true
view.delegate = context.coordinator
let compassBtn = MKCompassButton(mapView: view)
compassBtn.frame.origin = CGPoint(x: 20, y: 100) // you may use GeometryReader to replace it's position
compassBtn.compassVisibility = .adaptive // compass will always be on map
view.addSubview(compassBtn)
return view
}
func updateUIView(_ uiView: MKMapView, context: Context) {
//
print("Updating")
}
class Coordinator: NSObject,MKMapViewDelegate {
@Binding var center: CLLocationCoordinate2D?
init(center: Binding<CLLocationCoordinate2D?>) {
self._center = center
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// Custom Pins....
// Excluding User Blue Circle...
if annotation.isKind(of: MKUserLocation.self){return nil}
else{
let pinAnnotation = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "PIN_VIEW")
pinAnnotation.tintColor = .red
pinAnnotation.animatesDrop = true
pinAnnotation.canShowCallout = true
return pinAnnotation
}
}
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let currentLocation = mapView.centerCoordinate
print("? Координаты \(currentLocation)")
center = currentLocation
}
}
}
MapViewModel.swift
import SwiftUI
import MapKit
import CoreLocation
// All Map Data Goes Here....
class MapViewModel: NSObject,ObservableObject,CLLocationManagerDelegate{
@Published var center: CLLocationCoordinate2D?
@Published var mapView = MKMapView()
// Region...
@Published var region : MKCoordinateRegion!
// Based On Location It Will Set Up....
// Alert...
@Published var permissionDenied = false
// Map Type...
@Published var mapType : MKMapType = .standard
// SearchText...
@Published var searchTxt = ""
// Searched Places...
@Published var places : [Place] = []
// Updating Map Type...
func updateMapType(){
if mapType == .standard{
mapType = .hybrid
mapView.mapType = mapType
} else {
mapType = .standard
mapView.mapType = mapType
}
}
// Focus Location...
func focusLocation() {
guard let _ = region else{return}
mapView.setRegion(region, animated: true)
mapView.setVisibleMapRect(mapView.visibleMapRect, animated: true)
}
// Search Places...
func searchQuery(){
places.removeAll()
let request = MKLocalSearch.Request()
request.naturalLanguageQuery = searchTxt
// Fetch...
MKLocalSearch(request: request).start { (response, _) in
guard let result = response else{return}
self.places = result.mapItems.compactMap({ (item) -> Place? in
return Place(placemark: item.placemark)
})
}
}
// Pick Search Result...
func selectPlace(place: Place) {
// Showing Pin On Map....
searchTxt = ""
guard let coordinate = place.placemark.location?.coordinate else{return}
let pointAnnotation = MKPointAnnotation()
pointAnnotation.coordinate = coordinate
pointAnnotation.title = place.placemark.name ?? "No Name"
// Removing All Old Ones...
mapView.removeAnnotations(mapView.annotations)
mapView.addAnnotation(pointAnnotation)
// Moving Map To That Location...
let coordinateRegion = MKCoordinateRegion(center: coordinate, latitudinalMeters: 10000, longitudinalMeters: 1000 )
mapView.setRegion(coordinateRegion, animated: true)
mapView.setVisibleMapRect(mapView.visibleMapRect, animated: true)
}
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
// Checking Permissions...
switch manager.authorizationStatus {
case .denied:
// Alert...
permissionDenied.toggle()
case .notDetermined:
// Requesting....
manager.requestWhenInUseAuthorization()
case .authorizedWhenInUse:
// If Permissin Given...
manager.requestLocation()
default:()
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
// Error....
print(error.localizedDescription)
}
// Getting user Region....
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else{return}
self.region = MKCoordinateRegion(center: location.coordinate, latitudinalMeters: 10000, longitudinalMeters: 1000)
// Updating Map....
self.mapView.setRegion(self.region, animated: true)
// Smooth Animations...
self.mapView.setVisibleMapRect(self.mapView.visibleMapRect, animated: true)
print(location.coordinate)
}
}

