使用 swiftUI 进行聚类注释

Clustering annotation with swiftUI

我的目标是在地图上聚类注释并显示聚类中的项目数,我没有使用 UIKit 的经验并尽量避免它。是否可以仅使用 swiftUI 来完成?如果不是如何减少 UIKit 的干预? This is how it should look like

import SwiftUI
import MapKit

struct ContentView: View {

@State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 43.64422936785126, longitude: 142.39329541313924),
    span: MKCoordinateSpan(latitudeDelta: 1.5, longitudeDelta: 2)
)

   var body: some View {
    Map(coordinateRegion: $region, annotationItems: data) { annotation in
        MapAnnotation(coordinate: annotation.coordinate) {
            Image(systemName: "person.circle.fill")
                .resizable()
                .frame(width: 20, height: 20)
                .foregroundColor(Color.purple)
        }
    }
    .edgesIgnoringSafeArea(.all)
   }
}

struct SampleData: Identifiable {
var id = UUID()
var latitude: Double
var longitude: Double
var coordinate: CLLocationCoordinate2D {
    CLLocationCoordinate2D(
        latitude: latitude,
        longitude: longitude)
 }
}

var data = [
SampleData(latitude: 43.70564024126748, longitude: 142.37968945214223),
SampleData(latitude: 43.81257464206404, longitude: 142.82112322464369),
SampleData(latitude: 43.38416585162576, longitude: 141.7252598737476),
SampleData(latitude: 45.29168643283501, longitude: 141.95286751470724),
SampleData(latitude: 45.49261392585982, longitude: 141.9343973160499),
SampleData(latitude: 44.69825427301145, longitude: 141.91227845284203)
]

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

我找到了使用 MapKit 对注释进行聚类的方法,但像视图一样重用地图以实现简单的 swiftUI。看起来像 https://i.stack.imgur.com/u3hKR.jpg

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {


var forDisplay = data
@State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 43.64422936785126, longitude: 142.39329541313924),
    span: MKCoordinateSpan(latitudeDelta: 1.5, longitudeDelta: 2)
)


class Coordinator: NSObject, MKMapViewDelegate {
    
    var parent: MapView

    init(_ parent: MapView) {
        self.parent = parent
    }
    
/// showing annotation on the map
    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        guard let annotation = annotation as? LandmarkAnnotation else { return nil }
        return AnnotationView(annotation: annotation, reuseIdentifier: AnnotationView.ReuseID)
    }

}



func makeCoordinator() -> Coordinator {
    MapView.Coordinator(self)
}


func makeUIView(context: Context) -> MKMapView {
    ///  creating a map
    let view = MKMapView()
    /// connecting delegate with the map
    view.delegate = context.coordinator
    view.setRegion(region, animated: false)
    view.mapType = .standard
    
    for points in forDisplay {
        let annotation = LandmarkAnnotation(coordinate: points.coordinate)
        view.addAnnotation(annotation)
    }
    

    return view
    
}

func updateUIView(_ uiView: MKMapView, context: Context) {
    
}
}

struct SampleData: Identifiable {
var id = UUID()
var latitude: Double
var longitude: Double
var coordinate: CLLocationCoordinate2D {
CLLocationCoordinate2D(
    latitude: latitude,
    longitude: longitude)
 }
}

var data = [
SampleData(latitude: 43.70564024126748, longitude: 142.37968945214223),
SampleData(latitude: 43.81257464206404, longitude: 142.82112322464369),
SampleData(latitude: 43.38416585162576, longitude: 141.7252598737476),
SampleData(latitude: 45.29168643283501, longitude: 141.95286751470724),
SampleData(latitude: 45.49261392585982, longitude: 141.9343973160499),
SampleData(latitude: 44.69825427301145, longitude: 141.91227845284203)
]


class LandmarkAnnotation: NSObject, MKAnnotation {
let coordinate: CLLocationCoordinate2D
init(
     coordinate: CLLocationCoordinate2D
) {
    self.coordinate = coordinate
    super.init()
}
}


/// here posible to customize annotation view
let clusterID = "clustering"

class AnnotationView: MKMarkerAnnotationView {

static let ReuseID = "cultureAnnotation"

/// setting the key for clustering annotations
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
    super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
    clusteringIdentifier = clusterID
}


required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

override func prepareForDisplay() {
    super.prepareForDisplay()
    displayPriority = .defaultLow
 }
}

并将该地图用作默认视图

import SwiftUI

struct ContentView: View {


var body: some View {
MapView()
    .edgesIgnoringSafeArea(.all)
 }
}

为了解决问题,我使用了下一个资源:

https://www.hackingwithswift.com/books/ios-swiftui/communicating-with-a-mapkit-coordinator

https://www.hackingwithswift.com/books/ios-swiftui/advanced-mkmapview-with-swiftui

https://developer.apple.com/videos/play/wwdc2017/237/

https://www.youtube.com/watch?v=QuYA7gQjTt4