1

如何为用 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,所以请尽可能对初学者友好地解释。谢谢!

4

0 回答 0