tukuyo's blog

へっぽこマン

スポンサーリンク

SwiftUIでMapKitを使用してMapViewを作る【Part2】

はじめに

前回の記事では、SwiftUIでMapを表示することに成功しました。
また、表示するだけでなく、指定した位置をマップの初期中心に持ってきてピン(ポイントアノテーション)を打つことにも成功していました。
今回は、Map上をロングタップすることでピンを打てるようにします。

Coordinator を作成する

前回ピンを作成するために記述した部分は、必要がないので削除しておきます。
MapViewのなかにcoordinatorクラスを作成しましょう。

すると、メソッドを定義するようにXCodeが言ってくれるので
追加して、ついでに、delegateもCoordinatorに設定しましょう。

struct MapView: UIViewRepresentable {
    
    
    func makeUIView(context: Context) -> MKMapView {
        let map = MKMapView()
        map.delegate = context.coordinator
        return map
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

     // ビューの更新時に呼ばれる
    func updateUIView(_ mapView: MKMapView, context: Context) {
    }

    
    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapView

        init(_ parent: MapView) {
            self.parent = parent
        }
    }
}

Coordinatorに、ロングタップを検知するためのUILongPressGestureRecognizerの変数を追加しておきましょう。
そしてその変数にaddTargetするためのメソッドも定義して、addTargetに追加しておきましょう。

class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapView
        let myLongPress: UILongPressGestureRecognizer = UILongPressGestureRecognizer()

        init(_ parent: MapView) {
            self.parent = parent
            super.init()
            
            self.myLongPress.addTarget(self, action: #selector(recognizeLongPress))
        }
        
        @objc func recognizeLongPress(sender: UILongPressGestureRecognizer) {
            if sender.state == .began {
                print("In")
            } else if sender.state == .ended {
                print("Out")
            }
        }
    }

ロングタップされた時の処理をMKMapViewに認識させるために
mkmapviewに追加でジェスチャーを認識させ(?)ましょう。

func makeUIView(context: Context) -> MKMapView {
    let map = MKMapView()
    map.delegate = context.coordinator
    map.addGestureRecognizer(context.coordinator.myLongPress)  // 追加
    return map
}

ここでいったん実行してみましょう。
ロングタップし始めた時に 'In' 話した時に 'Out' がデバッグコンソールに出てくると思います。

出てきましたね。では、前回と同じようにピンを追加する処理を追加してあげましょう。
今回は、簡単にsender.stateが.endedの時にピンを置くようにしたいと思います。

@objc func recognizeLongPress(sender: UILongPressGestureRecognizer) {
        if sender.state == .ended {
            if let mapView = sender.view as? MKMapView {
                // タップした位置を取得
                let point = sender.location(in: mapView)
                // mapView上での位置に変換
                let coordinate = mapView.convert(point, toCoordinateFrom: mapView)
                // ピンの作成
                let annotation = MKPointAnnotation()
                annotation.coordinate = coordinate
                mapView.addAnnotation(annotation)
            }
        }
    }
}

おわりに

ロングタップでピンを置くことに成功しました。
ただ、ロングタップをした分だけピンが打たれてしまいます。
そこらへんの話はまた次回.






今回の記事のプロジェクトをGitHubに上げていますので是非ご覧ください。
間違いございましたら、是非教えていただきたいのでコメントお願いします。

それぞれの記事ごとにブランチを分けています。 github.com

今までの記事

前回までの記事は、以下から読めます。

blog.tukuyo.net

スポンサーリンク