このエントリーをはてなブックマークに追加

2016年12月7日水曜日

Swift3でMapKitの吹き出し(Callout)タップを取得したい!

こんにちは、onukiです。

今回、iOSのMapKitで吹き出しのタップを取得しようと思ったのですが、
これが案外簡単にいかなかったというか無理矢理やりました。(笑)

MKMapViewDelegateに以下のメソッドが用意されています
func mapView(_ mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
    //処理
}
ただ、こいつは基本的にMKAnnotationViewの
「leftCalloutAccessoryView」か「rightCalloutAccessoryView」にUIButton等のUIControlが取得できるものを配置し、
そして、そのボタンを押すなどした時に、このメソッドが呼ばれます。
しかし、今回やりたいことはGoogleMapみたいに吹き出しのどこでもタップできるようにしたいという事。
(というか吹き出しにボタンを配置したくない。。。)

というわけで結論を早々に述べるとMKAnnotationViewに直接UITapGestureRecognizerを設定します。
MapKitはピンを刺すときにMKAnnotationViewを使用していますがピン部分だけではなく
吹き出し(Callout)部分もSubViewではなくピンと一緒にMKAnnotationViewとして扱われています。
なので以下のようにすると吹き出し部分のタップも取得できます。
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
    let tapGesture = UITapGestureRecognizer(target: self, action: #selector(hoge.tapGesture(gestureRecognizer:)))
    view.addGestureRecognizer(tapGesture)
}
これで吹き出し部分のタップが取得できます!

ですが、このままだとピン画像(MKAnnotationView.image)の部分もタップできてしまうので、
タップ処理側で以下のような条件を付けます。
func tapGesture(gestureRecognizer: UITapGestureRecognizer){
    let view = gestureRecognizer.view
    let tapPoint = gestureRecognizer.location(in: view)
    //ピン部分のタップだったらリターン
    if tapPoint.x >= 0 && tapPoint.y >= 0 {
        return
    }
    //処理
}

なぜこれでいけるかというと、MKAnnotationView自体のフレームはピン画像部分のみで
吹き出し部分はMKAnnotationViewのフレーム外に描画されています。

以上、だいぶ無理矢理タップ判定しましたが
これでGoogleMapと同じく吹き出しのどこをタップされても取得することができます。
(もっとスマートなやり方ご存知の方、ご教授いただけると幸いです)

0 件のコメント:

コメントを投稿