如何为用 SwiftUI 编写的 MapKitAnnotations 添加自定义 calloutView?
我目前有这个代码:
import SwiftUI
import MapKit
import CoreLocation
import UIKit
struct MapView: UIViewRepresentable {
@Binding var userTrackingMode: MKUserTrackingMode
@Binding var centerCoordinate: CLLocationCoordinate2D
@Binding var selectedPlace: MKPointAnnotation?
@Binding var showingPlaceDetails: Bool
var annotations: [MKPointAnnotation]
var locationManager = CLLocationManager()
func setupManager() {
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.requestAlwaysAuthorization()
}
//Static
func makeUIView(context: Context) -> MKMapView {
//setupManager()
let mapView = MKMapView()
mapView.delegate = context.coordinator
mapView.showsUserLocation = true
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
mapView.setUserTrackingMode(.follow, animated: true)
mapView.showsCompass = false
// add annotation for Technical University and Mensa
let annotation = MKPointAnnotation()
annotation.title = "London"
annotation.subtitle = "Capital of England"
annotation.coordinate = CLLocationCoordinate2D(latitude: 51.5, longitude: 0.13)
mapView.addAnnotation(annotation)
return mapView
}
//Dynamic
func updateUIView(_ uiView: MKMapView, context: Context) {
if uiView.userTrackingMode != userTrackingMode {
uiView.setUserTrackingMode(userTrackingMode, animated: true)
}
if annotations.count != uiView.annotations.count {
uiView.removeAnnotations(uiView.annotations)
uiView.addAnnotations(annotations)
}
print("updating")
}
//Initialise UIKit Map Coordinator
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, MKMapViewDelegate {
var parent: MapView
init(_ parent: MapView) {
self.parent = parent
}
func mapViewDidChangeVisibleRegion(_ mapView: MKMapView) {
parent.centerCoordinate = mapView.centerCoordinate
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else {
return nil
}
let identifier = "Placemark"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
//CALL ANNOTATION VIEW
annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
annotationView?.canShowCallout = true
// annotationView?.rightCalloutAccessoryView = UIButton(type: .detailDisclosure)
annotationView?.rightCalloutAccessoryView = UIHostingController(rootView: PopupView()) // THIS LINE RIGHT HERE!
} else {
annotationView?.annotation = annotation
}
return annotationView
}
func mapView(_ mapView: MKMapView, didChange mode: MKUserTrackingMode, animated: Bool) {
if mode != parent.userTrackingMode {
DispatchQueue.main.async {
self.parent.userTrackingMode = mode
}
}
}
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
guard let placemark = view.annotation as? MKPointAnnotation else { return }
parent.selectedPlace = placemark
parent.showingPlaceDetails = true
}
}
}
extension MKUserTrackingMode {
fileprivate var description: String {
switch self {
case .follow: return "follow"
case .followWithHeading: return "followWithHeading"
case .none: return "none"
@unknown default: return "unknown"
}
}
}
协调器中的viewForAnnotation
方法是重点,我认为我必须添加一些东西,但是什么?我没有使用 Storyboard 或任何东西,我只想在地图上的 SwiftUI 中自定义弹出窗口。我不太熟悉 UIKit,所以请尽可能对初学者友好地解释。谢谢!