'MKMapView inside NavigationView when clicking MKAnnotation is glitchy
Below is some code you can copy paste inside a new project in Xcode inside the ContentView.swift file. This is what I want:
- A map with annotations
- When an annotation is clicked, a
NavigationViewshould redirect the user to a detailed screen - When the user navigates back to the map, the map is at the exact same spot as when the user clicked the annotation
- The detailed screen has a property that MUST be initialized in the
initmethod of the struct itself, no environment objects
I want to do this in MKMapView since I want to support clustering and overlays, something that is not available right now with the native SwiftUI Map.
The code that I have is glitchy. When the user navigates back to the map, the map is completely white for a second. After that second, the map is zoomed out so the user isn't at the exact same spot as before.
I did wrap the NavigationLink and MapView inside a ZStack but then the NavigationView does not animate when it is clicked.
This is the code:
import MapKit
import SwiftUI
struct AnnotationView: View {
let annotation: Annotation
var body: some View {
Text("Not important")
}
}
struct ContentView: View {
@State private var selectedAnnotation: Annotation? = nil
@State private var didSelectAny = false
var body: some View {
NavigationView {
Group {
if didSelectAny {
if let annotation = selectedAnnotation {
NavigationLink(destination: AnnotationView(annotation: annotation), isActive: $didSelectAny) {}
}
}
MapView { annotation in
selectedAnnotation = annotation
didSelectAny = true
}
}.navigationBarTitle("Map")
}
.navigationViewStyle(.stack)
}
}
class MapViewCoordinator: NSObject, MKMapViewDelegate {
var mapViewController: MapView
init(_ control: MapView) {
mapViewController = control
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? Annotation else { return nil }
let identifier = "Annotation"
var annotationView = mapView
.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKAnnotationView(
annotation: annotation,
reuseIdentifier: identifier
)
} else {
annotationView!.annotation = annotation
}
annotationView!.image = UIImage(systemName: "person.2")!
return annotationView
}
func mapView(_ map: MKMapView, didSelect view: MKAnnotationView) {
guard
let annotationView = view.annotation,
let annotation = annotationView as? Annotation
else {
// Could be current users location
return
}
annotation.didSelect(annotation)
map.deselectAnnotation(annotationView, animated: false)
}
}
struct MapView: UIViewRepresentable {
let didSelect: (Annotation) -> Void
func makeUIView(context _: Context) -> MKMapView {
MKMapView()
}
func makeCoordinator() -> MapViewCoordinator {
MapViewCoordinator(self)
}
func updateUIView(_ view: MKMapView, context: Context) {
let center = CLLocationCoordinate2D(latitude: 10, longitude: 10)
view.delegate = context.coordinator
view.region = .init(center: center, span: .init(latitudeDelta: 0.1, longitudeDelta: 0.1))
let annotation = Annotation(didSelect: didSelect)
annotation.coordinate = center
view.addAnnotation(annotation)
}
}
class Annotation: MKPointAnnotation {
let didSelect: (Annotation) -> Void
init(
didSelect: @escaping (Annotation) -> Void
) {
self.didSelect = didSelect
super.init()
title = "title"
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
