简体   繁体   English

UIViewRepresentable - MKMapView 没有得到更新

[英]UIViewRepresentable - MKMapView doesn't get updated

I'm dealing with an app where I have to embed a MKMapView (UIKit) into a SwiftUI View.我正在处理一个应用程序,我必须将MKMapView (UIKit) 嵌入到 SwiftUI 视图中。 Unfortunately I can't use the implemented Map of SwiftUI, because I have to support clustering (which Map can't do at the moment).不幸的是,我不能使用 SwiftUI 的实现Map ,因为我必须支持集群(目前Map不能做)。
The problem is, that the MKMapView doesn't reflect changes applied to the data source ( persons array).问题是, MKMapView不反映应用于数据源( persons数组)的更改。

ContentView内容视图

struct ContentView: View {
    @State private var persons: [Person] = [
        .init(
            coordinate: .init(latitude: 50.7123012, longitude: 5.1231021),
            title: "Person 1"
        ),
        .init(
            coordinate: .init(latitude: 49.3123012, longitude: 5.1231021),
            title: "Person 2"
        )
    ]
    
    var body: some View {
        VStack {
            MapView(persons: $persons)
            Button("Remove Person at index 0") {
                persons.remove(at: 0)
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Implementation of MKMapView with the help of UIViewRepresentable :借助UIViewRepresentable实现MKMapView

struct MapView: UIViewRepresentable {
    @Binding var persons: [Person]
    private let mapView = MKMapView()
    
    init(persons: Binding<[Person]>) {
        self._persons = persons
        // other stuff
    }
    
    func makeUIView(context: Context) -> MKMapView {
        mapView.delegate = context.coordinator
        mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "testAnnotation")
        return mapView
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        DispatchQueue.main.async {
            mapView.removeAnnotations(mapView.annotations)
            mapView.addAnnotations(persons)
        }
    }
}

extension MapView {
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, MKMapViewDelegate {
        
        var parent: MapView
        
        init(_ parent: MapView) {
            self.parent = parent
        }

        func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
            if let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: "testAnnotation", for: annotation) as? MKMarkerAnnotationView {
                annotationView.glyphImage = UIImage(systemName: "person")
                return annotationView
            }
            
            return nil
        }
    }
}

Demo Model:演示模型:

class Person: NSObject, MKAnnotation {
    var coordinate: CLLocationCoordinate2D
    let title: String?
    
    init(coordinate: CLLocationCoordinate2D, title: String?) {
        self.coordinate = coordinate
        self.title = title
    }
}

Please note, that this is a simplified implementation where I removed logic for clustering, etc. to focus on the problem.请注意,这是一个简化的实现,我删除了集群逻辑等以专注于问题。

在此处输入图像描述


If you tap on "Remove Person at index 0" it actually removes the entry at index 0 but unfortunately the map isn't updated.如果您点击“删除索引 0 处的人员”,它实际上会删除索引 0 处的条目,但不幸的是地图没有更新。 The problem is that updateUIView in MapView doesn't get called and I'm not sure, why this is the case.问题是MapView中的updateUIView没有被调用,我不确定为什么会这样。
Thanks for your help :-)...谢谢你的帮助 :-)...

Two issues create map view inside makeView - that's a place for that by design, update annotations right in update (no delay needed) it is a place called on binding update exactly to update UIView counterpart (all UI invalidation/refreshing is made automatically)两个问题在makeView中创建地图视图 - 这是一个设计的地方,在更新中更新注释(不需要延迟)它是一个调用绑定更新的地方,以更新 UIView 对应项(所有 UI 失效/刷新都是自动进行的)

So, here is fixed version.所以,这里是固定版本。 Tested with Xcode 13.4 / iOS 15.5使用 Xcode 13.4 / iOS 15.5 测试

演示

struct MapView: UIViewRepresentable {
    @Binding var persons: [Person]

    init(persons: Binding<[Person]>) {
        self._persons = persons
        // other stuff
    }

    func makeUIView(context: Context) -> MKMapView {

        let mapView = MKMapView()      // << here !!

        mapView.delegate = context.coordinator
        mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: "testAnnotation")
        return mapView
    }

    func updateUIView(_ mapView: MKMapView, context: Context) {

        mapView.removeAnnotations(mapView.annotations)    // << here !!
        mapView.addAnnotations(persons)

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM