【SwiftUI】地図上にタップ/長押しでピンを設置する方法!MapKit

この記事からわかること
- Swift UIで地図(Maps)を表示する方法
- MapKitフレームワークの使い方
- 地図上をタップ/長押しでピンを設置と住所を表示する方法
- UITapGestureRecognizer/UILongPressGestureRecognizerの使用方法
index
[open]
\ アプリをリリースしました /
環境
- Xcode:16.0
- iOS:18.0
- Swift:5.9
- macOS:Sonoma 14.6.1
SwiftUIにMapKitを導入して地図を表示するアプリの開発中にユーザーからのタップ/長押し時に地図上にピンを設置する機能を実装したので方法を解説していきます。
SwiftUiでMKMapViewを使用する
SwiftUIを使用して地図を表示させる場合はMapView構造体
を使用して地図を表示させますが、2022年8月26日現在ユーザーからのタップなどのイベントを取得して地図上に反映させる方法が見つかりませんでした。
なので仕方なくUIKit
ビューをSwiftUIに使用できるようにするUIViewRepresentable
プロトコルを使ってMKMapView
をSwiftUIで使用できるようにして実装していきます。
流れ
- SwiftUiでMKMapViewを使用するためのビュー構造体を作成
- Coordinatorクラスを追加してイベント時の処理を記述
- UITapGestureRecognizer/UILongPressGestureRecognizerでイベントを取得
注意:SwiftUIとUIKitのMapKitの使い方は少し異なります。今回はタップイベントを実装するためにUIKitの場合の地図表示方法で進んでいきますが地図を表示するだけであればSwiftUIのMapView構造体で簡単に表示できますのでこちらの記事をご覧ください。
タップされた場所にピンを設置する方法
地図上をタップされた時にその場所にピンを設置する方法を見ていきます。
まずはUIKitのMkMapViewをSwiftUIでも表示できるようにUIViewRepresentable
プロトコルを使用したビュー構造体を定義します。
ここでは特に変わった処理はありません。プロパティにはMKMapView
インスタンスを用意しておきます。
Coordinatorクラスにイベント処理の追加
続いてUIKitのイベントをSwift UIで管理するためのCoordinatorクラスを追加します。プロパティにはビュー構造体のMKMapViewをバインディングできるようにしておきます。タップされた時に実行したい処理はtapped
メソッドとして記述していきます。
タップされた地図上の座標を取得する
tappedメソッドのコードの流れ
- タップされた情報を取得(引数:gesture)
- ビューのポイントを取得
- ポイントをマップの座標に変換
- 座標を元にアノテーションを構築
- 定義ずみのアノテーションがあれば削除
- アノテーションをビューに追加
引数にはUITapGestureRecognizer
クラスを指定しておきます。これでタップされた際の情報を引数名gesture
で取得できるようになります。
UIGestureRecognizer.location(in view: UIView?)メソッド
タップされた地図上の座標を取得するにはUIGestureRecognizer
クラスのlocation(in:)
メソッドを使います。引数に指定したビュー内の場所を返してくれるのでMKMapView
を指定するとMapビューのポイントを返してくれます。
MKMapView.convertメソッド
ビューのポイントから地図座標に変換するにはMKMapView
のconvert
メソッドを使用します。引数には変換するCGPoint
型の値とビューインスタンスを指定します。
MKPointAnnotationクラス
アノテーションはMKPointAnnotation
クラスを使って構築していきます。
MKMapView.removeAnnotationメソッド
タップされる度にアノテーションを増やしたくないので追加前にアノテーションをリセットします。アノテーションの有無を識別し、あれば1つしかないはずなので決め打ちで[0]
をremoveAnnotation
で削除します。
最後にアノテーションをビューに追加して終了です。
makeCoordinatorの追加
Coordinatorクラスを増やしたのでUIMapAddressGetView
構造体にはmakeCoordinator
メソッドを追加しておきます。
UITapGestureRecognizerでタップイベントを追加
続いてタップされた時のイベント処理をビューに追加するためにmakeUIView
メソッドの中からUITapGestureRecognizer
を使用してイベント処理を定義し、addGestureRecognizer
を使ってmapViewのイベントに追加しておきます。
これでタップした位置にアノテーションを設置する機能が完了しました。
全体のコードは以下の通りです。
長押しされた場所にピンを設置する方法
タップの場合だと通常の地図操作の際にもピンが設置されてしまう可能性があるので長押しした場合のみピンを設置するように実装してみます。
長押しの場合は先程のコードのUITapGestureRecognizer
部分をUILongPressGestureRecognizer
に変えるだけです。今回はメソッド名も変更しておきました。
長押しされた場所の住所を取得する
ユーザーが長押しした場所の住所を取得できるようにしていきます。ビュー構造体とCoordinatorクラスにaddress
プロパティを追加し、長押しされたポイントの住所が格納されるようにしていきます。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。
私がSwift UI学習に使用した参考書