はじめに
MKMapKitを使うと簡単に地図やピンが描画できてとても便利ですが、
クラスター化されたピンをタップした際のデータ取得に少し苦労したので、簡単にまとめておきます。
環境
Xcode 12.4
Swift 5.3.2
実現したかった事
- 緯度軽度とIDの情報を持ったピンを生成
- ピンのUIはシンプルに、文字の表示もしない
- 全てのピンは物理接触でクラスター化され、クラスターピンには数字を表示
- ピンをタップしたら画面遷移させ、その際ピンに含まれるIDを渡す
実装
まずは、カスタムアノテーションを作る。
class CustomAnnotation: NSObject, MKAnnotation {
// クラスターID
static let clusteringIdentifier = "locationCluster"
// ピンの緯度軽度
let coordinate: CLLocationCoordinate2D
// ピンのID
let title: String?
init(_ coordinate: CLLocationCoordinate2D, id: Int) {
self.coordinate = coordinate
title = String(id)
}
}
次に地図画面の実装(関係する箇所のみ)
extension MapViewController: MKMapViewDelegate {
// ピンを地図に描画する(初期表示やデータ更新時)
private func drawPinsOnMap() {
let span = MKCoordinateSpan(latitudeDelta: spanLatitudeDelta, longitudeDelta: spanLongitudeDelta)
let center = CLLocationCoordinate2DMake(centerLatitude, centerLongitude)
let region = MKCoordinateRegion(center: center, span: span)
mapView.region = region
var annotations: [MKAnnotation] = []
mapView.removeAnnotations(mapView.annotations)
let mapData = viewModel.dataArray.value //データ取得
guard mapData.count > 0 else { return }
for data in mapData {
let pin = CustomAnnotation(CLLocationCoordinate2DMake(data.latitude, data.longitude), id: data.id)
annotations.append(pin)
}
mapView.addAnnotations(annotations)
}
// アノテーションビューの生成
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
return nil
} else if annotation is MKClusterAnnotation {
let clusterAnnoationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier, for: annotation)
guard let safeCluster = clusterAnnoationView as? MKMarkerAnnotationView else { return clusterAnnoationView }
safeCluster.titleVisibility = .hidden
safeCluster.subtitleVisibility = .hidden
return safeCluster
}
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier, for: annotation)
guard let markerAnnotationView = annotationView as? MKMarkerAnnotationView, let _ = annotation as? CustomAnnotation else {
return annotationView
}
markerAnnotationView.clusteringIdentifier = CustomAnnotation.clusteringIdentifier
markerAnnotationView.titleVisibility = .hidden
markerAnnotationView.subtitleVisibility = .hidden
return markerAnnotationView
}
// 地図上のピン押下時の処理
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
var idList: [Int] = []
// ここでクラスターピンか単体ピンか確認して処理を変える
if let cluster = view.annotation as? MKClusterAnnotation {
let annotations = cluster.memberAnnotations
for annotation in annotations {
guard let title = annotation.title as? String else { continue }
guard let id = Int(title) else { continue }
idList.append(id)
}
} else {
guard let pin = view.annotation else { return }
guard let title = pin.title as? String else { return }
guard let id = Int(title) else { return }
photoIdList.append(id)
}
// ★ ここでidListを持って画面遷移させる
// 必要に応じてピンのセレクト状態を解除する
mapView.deselectAnnotation(view.annotation, animated: true)
}
}
結果
if let cluster = view.annotation as? MKClusterAnnotation {
let annotations = cluster.memberAnnotations
}
でクラスターピンの持っている情報が取得できました。
感想
結果的に大したことなかった実装でしたが、クラスターピンからなかなかピンの情報が取得できず、ドキュメントを読みながら色々工夫してやっとできました。
参考記事