はじめに
こんにちは、nukkyです。
今回、iOSのMapKitでGoogleMapのように
吹き出しのタップを取得しようと思ったのですが、
これが案外簡単にいかなかったというか無理矢理やりました。(笑)
MapKitでの吹き出しタップ
MKMapViewDelegateに以下のメソッドが用意されています
1 2 3 | func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) { //処理 } |
ただ、こいつは基本的にMKAnnotationViewの
「leftCalloutAccessoryView」か「rightCalloutAccessoryView」にUIButton等のUIControlが取得できるものを配置し、
そして、そのボタンを押すなどした時に、このメソッドが呼ばれます。
しかし、今回やりたいことはGoogleMapみたいに吹き出しのどこでもタップできるようにしたいという事。
(というか吹き出しにボタンを配置したくない。。。)
吹き出しのみタップしたい!
というわけで結論を早々に述べるとMKAnnotationViewに直接UITapGestureRecognizerを設定します。
MapKitはピンを刺すときにMKAnnotationViewを使用していますがピン部分だけではなく
吹き出し(Callout)部分もSubViewではなくピンと一緒にMKAnnotationViewとして扱われています。
なので以下のようにすると吹き出し部分のタップも取得できます。
1 2 3 4 | func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) { let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hoge.tapGesture(gestureRecognizer:))) view.addGestureRecognizer(tapGesture) } |
これで吹き出し部分のタップが取得できます!
ですが、このままだとピン画像(MKAnnotationView.image)の部分もタップできてしまうので、
タップ処理側で以下のような条件を付けます。
1 2 3 4 5 6 7 8 9 | func tapGesture(gestureRecognizer: UITapGestureRecognizer){ let view = gestureRecognizer.view let tapPoint = gestureRecognizer.location(in: view) //ピン部分のタップだったらリターン if tapPoint.x >= 0 && tapPoint.y >= 0 { return } //処理 } |
なぜこれでいけるかというと、MKAnnotationView自体のフレームはピン画像部分のみで
吹き出し部分はMKAnnotationViewのフレーム外に描画されていますので
タップしたxとyの位置がフレーム内であればそこがピン画像になります。
さいごに
以上、だいぶ無理矢理タップ判定しましたが
これでGoogleMapと同じく吹き出しのどこをタップされても取得することができます!
もし同じことで悩んでる方がいたら参考にしていただければと思います。
(もっとスマートなやり方ご存知の方、ご教授いただけると幸いです。。。)