SwiftUI 中的自定义注解 (MKMapView)

Custom Annotations in SwiftUI (MKMapView)

我在 SwiftUI 中实现了一个 MKMapView,我正在显示注释(停靠点)列表以及用户的位置。 我想将水龙头功能添加到“停止引脚”,但我找不到任何有助于实现此目的的东西。

此代码的问题在于它更改了用户定位图钉的视图并最终因以下错误而崩溃。

2021-07-10 18:31:21.434538+0900 Bus Finder[5232:2086940] *** Terminating app due to uncaught exception 'NSGenericException', reason: '<Bus_Finder.Stops: 0x2816c4cc0> must implement title, or view (null) must have a non-nil detailCalloutAccessoryView when canShowCallout is YES on corresponding view <MKAnnotationView: 0x13137cd60; frame = (-20 -20; 40 40); opaque = NO; layer = <CALayer: 0x2832e9e20>>'
*** First throw call stack:
(0x196f2a754 0x1ab9f17a8 0x1a6566410 0x1a65655bc 0x1a656464c 0x1a65641d0 0x1982fd458 0x196ea522c 0x196ea4e28 0x196ea4278 0x196e9e02c 0x196e9d360 0x1ae4db734 0x199918584 0x19991ddf4 0x19ddf3370 0x19ddf32fc 0x19d8ebb6c 0x100eacf54 0x100eacff4 0x196b59cf8)
libc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSGenericException', reason: '<Bus_Finder.Stops: 0x2816c4cc0> must implement title, or view (null) must have a non-nil detailCalloutAccessoryView when canShowCallout is YES on corresponding view <MKAnnotationView: 0x13137cd60; frame = (-20 -20; 40 40); opaque = NO; layer = <CALayer: 0x2832e9e20>>'
terminating with uncaught exception of type NSException

我只想更改“stops pin”的视图并添加点击功能。 我在出现时将停止列表传递给 MapViewStops结构在最后。

我的问题的视觉概念:

(注释viewFor注解函数时) 我想更改停止图钉的样式并向其添加点击功能,而不是用户的位置图钉。

当我使用 viewFor 注释功能(与本问题中的代码相同)时,用户位置视图发生变化,然后应用程序崩溃。

MapView 文件:

// MARK: MapView
struct MapView: UIViewRepresentable {
    
    // MARK: Variables
    @Binding var stops: [Stops]
    @Binding var centerCoordinate: MKCoordinateRegion
    @Binding var action: Action
    
    // MARK: Action Lists
    enum Action {
        case idle
        case reset(coordinate: MKCoordinateRegion)
        case changeType(mapType: MKMapType)
    }
    
    // MARK: First Time Only
    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        mapView.delegate = context.coordinator
        mapView.showsUserLocation = true
        mapView.userTrackingMode = .follow
        mapView.isUserInteractionEnabled = true
        mapView.centerCoordinate = self.centerCoordinate.center
        mapView.setRegion(self.centerCoordinate, animated: true)
        return mapView
    }
    
    // MARK: Updating UI
    func updateUIView(_ view: MKMapView, context: Context) {
        switch action {
        case .idle:
            break
        case .reset(let newCoordinate):
            view.delegate = nil
            
            DispatchQueue.main.async {
                self.centerCoordinate.center = newCoordinate.center
                self.action = .idle
                view.setRegion(self.centerCoordinate, animated: true)
                view.delegate = context.coordinator
            }
        case .changeType(let mapType):
            view.mapType = mapType
        }
        view.addAnnotations(stops)
    }
    
    // MARK: Setting 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.center = mapView.centerCoordinate
            
        }
        
        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            let annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "TESTING NOTE")
            annotationView.canShowCallout = true
            annotationView.image = UIImage(systemName: "location.circle")?.withTintColor(.systemGreen, renderingMode: .alwaysOriginal)
            let size = CGSize(width: 40, height: 40)
            annotationView.image = UIGraphicsImageRenderer(size:size).image {
                _ in annotationView.image!.draw(in:CGRect(origin:.zero, size:size))
            }
            return annotationView
        }
        
    }
}

Stops结构文件:

// MARK: StopPinPoint
final class Stops: NSObject, Codable, Identifiable, MKAnnotation {
    
    var id: String?
    var name: BusStopName
    var images: [String]?
    var landMarks: [String]?
    var coordinate: CLLocationCoordinate2D
    var prevNexStop: [String]?
    
    init(id: String?, name: BusStopName, images: [String]?, landMarks: [String]?, coordinates: CLLocationCoordinate2D, prevNextStop: [String]?) {
        self.id = id
        self.name = name
        self.coordinate = coordinates
        self.images = images
        self.landMarks = landMarks
        self.prevNexStop = prevNextStop
    }
    
    var location: CLLocation {
        return CLLocation(latitude: self.coordinate.latitude, longitude: self.coordinate.longitude)
    }
    
    func distance(to location: CLLocation) -> CLLocationDistance {
        return location.distance(from: self.location)
    }
}

如果有人能帮助我,我将不胜感激!几个星期以来我一直在研究这个问题!

所以基本上在多搜索之后,我找到了答案。

为了不改变用户的位置 pin,我必须检查注释的类型,如果类型是 MKUserLocation 我应该 return nil。

接下来崩溃的原因是我必须让 Stops 结构确认 MKPointAnnotation 并删除或覆盖坐标变量然后当我制作 [=11 的列表时=] 我可以简单地定义标题、副标题和坐标。