【Swift】MKMapView:ピンに画像やCustomViewを設定する
こんにちは。
今まで触る機会がなかったMapViewを実装する機会がありまして、色々とメモしたいことがあるので備忘録です。
今回はピンにCustomViewを設定する話です。
Annotationに画像を設定したい場合
デフォルトのピンではなく、独自のデザインを設定したい場合は画像として設定するのが早いです。
なお、このピンはAnnotationというので以下でそう使います。
Annotationをマップに落とす場合は以下のようにmapViewに必要な分のAnnotationを追加します。
private func setAnnotations() {
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: 35.68493104294112, longitude: 139.75273538025138)
mapView.addAnnotation(annotation)
}
MKMapViewDelegate の ViewFor で画像を設定します。
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// ignore UserLocation
if annotation is MKUserLocation { return nil }
let identifier = "pin"
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
} else {
annotationView?.annotation = annotation
}
// set custom image
annotationView?.image = R.image.ic_annotation()
return annotationView
}
Annotationにカスタムビューを設定したい場合
ただ画像を変えたいだけなら上記で問題ないですが、Annotationに番号をふったり、Annotationに乗る情報を動的に設定したい場合はCustomViewを設定するといいです。
色々説明したい部分があるので分けて説明します。
MKPointAnnotation のカスタムクラスを作成する
加工などは基本的に mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation)
で行うので、値を設定しやすいように MKPointAnnotation
のカスタムクラスを作成し値を持たせます。
class PlaceAnnotation: MKPointAnnotation {
let index: String
var name: String
var image: UIImage
var latitude: Double
var longitude: Double
init(index: Int, name: String, image: UIImage, latitude: Double, longitude: Double) {
self.index = index.description
self.name = name
self.image = image
self.latitude = latitude
self.longitude = longitude
}
}
データは入れたい情報、なんでもいいですが、APIから取得してきたりするケースが多いと思うのでそのデータを持たせたりするといいと思います。
MKAnnotationView のカスタムクラスを作成する
接待したいViewのカスタムクラスを作成します。
この場合は MKAnnotationView
を継承します。
import UIKit
import MapKit
final class PlaceAnnotationView: MKAnnotationView {
@IBOutlet weak var label: UILabel!
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
centerOffset = CGPoint(x: 0, y: -frame.size.height / 2)
loadFromNib()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadFromNib()
}
private func loadFromNib() {
let nib = R.nib.placeAnnotationView
guard let view = nib.instantiate(withOwner: self).first as? UIView else { return }
view.frame = bounds
addSubview(view)
}
}
中心位置を修正するために centeroffset
に少し手を加えます。
注意点として、xibで作成する場合はsuperviewに制約を上下左右合わせないようにしてください。
このようにレイアウトがうまく表示されません。
このようにwidth / height で基本となるViewのサイズを取るとうまくいきます。
DelegateにAnnotationを設定する
最後にDelegateメソッドにAnnotationの設定を記述します。
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// ignore UserLocation
if annotation is MKUserLocation { return nil }
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier) as? PlaceAnnotationView
if let annotation = annotation as? PlaceAnnotation {
annotationView?.label.text = annotation.index
}
return annotationView
}
異なるCustomViewを複数利用したい場合は、その分 register
し、上記で説明した画像の入れ替えだけを行うAnnotationと混ぜたい場合も、viewFor
内で分けて設定すれば実現できます。
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
// ignore UserLocation
if annotation is MKUserLocation { return nil }
switch annotation {
case is PlaceAnnotation:
let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier) as? PlaceAnnotationView
if let annotation = annotation as? PlaceAnnotation {
annotationView?.label.text = annotation.index
}
return annotationView
default:
let identifier = "pin"
var annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
if annotationView == nil {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: identifier)
} else {
annotationView?.annotation = annotation
}
annotationView?.image = R.image.ic_annotation()
return annotationView
}
}
静的表示を行いたい場合はregisterさえすれば特にDelegateの実装はしなくて済みます。
表示に関しては以上です!
終わりに
MapViewは今まで利用する機会がなくいい経験ができてよかったです、この辺はどの案件でも使いそうな知見ですし、、
よかったら参考にしてみてくださいな。
ディスカッション
コメント一覧
まだ、コメントがありません