38. Карта с кластеризацией в SwiftUI
В ходе работы над приложением с площадками для воркаута я разобрался как реализовать в SwiftUI карту с кластеризацией (объединение рядом стоящих точек при отдалении) и сейчас покажу как это делается.
На момент публикации статьи (октябрь 2023 года) карта в SwiftUI до сих пор не умеет в кластеризацию, поэтому нам пригодится MKMapVIew и UIViewRepresentable 😁
Скриншоты экрана с применением такой карты:
На что нужно обратить внимание
1) makeUIView - тут карта создается "в первый раз", но чтобы избежать дублей, можно один раз сохранить готовый экземпляр и обращаться к нему в следующий раз:
let view = if let storedView = MapView991.storedMapView {
storedView
} else {
MKMapView()
}
...
return view
2) updateUIView - тут происходит обновление карты, например при изменении набора точек для отображения (при фильтрации, как вариант), или при изменении региона карты. Важно правильно проверить точки и регион, чтобы карта не мерцала из-за лишних обновлений. В случае с моей картой я фильтрую кластеры и точку самого пользователя перед сопоставлением точек:
RegionOrganizer(old: mapView.region, new: region) .updateRegionIfNeeded(for: mapView) AnnotationsOrganizer(old: mapView.annotations, new: annotations) .updateAnnotationsIfNeeded(for: mapView)
3) mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) - а тут как раз создаются точки для отображения, в том числе кластеры:
let view: MKMarkerAnnotationView
switch annotation {
case is MKUserLocation: return nil // игнорируем дефолтную точку с пользователем
case is MKClusterAnnotation: // делаем кластер
view = mapView.dequeueReusableAnnotationView(withIdentifier: clusterID) as? MKMarkerAnnotationView
?? .init(annotation: annotation, reuseIdentifier: clusterID)
...
default: // делаем обычную точку
view = mapView.dequeueReusableAnnotationView(withIdentifier: annotationID) as? MKMarkerAnnotationView
?? .init(annotation: annotation, reuseIdentifier: annotationID)
...
}
return view
Библиотеку можно посмотреть тут, а почитать другие статьи - тут.