SwiftUI で Map を表示するには、iOS13 では こちらのQiita記事 のように UIViewRepresentable を使って カスタムView を作成する必要がありました。
しかし、iOS14 から「Map」という SwiftUI 用の View が標準で搭載され、実装が大変簡略化されました。
今回はこの Map についての使い方の紹介していきたいと思います。
SwiftUI で Map を表示する手順
(1) MapKit のインポート
Map という View で表示できるようにはなりましたが、引数として渡す各種データを定義するにはMapKit ライブラリのインポートは依然として必要です。
import MapKit
これが無いとビルドエラーになりますので先ずはお忘れなきよう。
(2) MKCoordinateRegion
利用頻度の高い以下のイニシャライザーには位置情報となる MKCoordinateRegion の状態変数が必要になります(不要なイニシャライザーもありますが今回はそちらの解説はしません)。
①MKCoordinateRegion(center: CLLocationCoordinate2D, latitudinalMeters: CLLocationDistance, longitudinalMeters: CLLocationDistance)
②MKCoordinateRegion(center: CLLocationCoordinate2D, span: MKCoordinateSpan)
1) center: CLLocationCoordinate2D
表示領域の中心位置を緯度経度で指定します。
2) latitudinalMeters: CLLocationDistance
緯度に対しての表示領域をメートルで指定します。例えば 100 を指定した場合、中心位置から西に100m、東に100mが表示領域なります。
3) longitudinalMeters: CLLocationDistance
経度に対しての表示領域をメートルで指定します。例えば 100 を指定した場合、中心位置から北に100m、南に100mが表示領域となります。
4) span: MKCoordinateSpan
緯度・経度それぞれに対する表示領域をそれぞれの縮尺(単位は度)で指定します。1度で約111kmあるそうなので比較的小さい値を指定することが多いと思います。例えば、100m を縮尺で表すと 0.0009 くらいになります。
実際は以下のように宣言します。
@State private var region =
MKCoordinateRegion(
center: .init(latitude: 35.710263046992736, longitude: 139.81067894034084),
latitudinalMeters: 300,
longitudinalMeters: 300
)
@State private var region =
MKCoordinateRegion(
center: .init(latitude: 35.710263046992736, longitude: 139.81067894034084),
span: MKCoordinateSpan(latitudeDelta: 0.0009, longitudeDelta: 0.0009)
)
(3) シンプルに表示してみる
Map には表示領域だけのイニシャライザーと、ピンなどを設置する複雑なイニシャライザーがありますが、先ずは前者のイニシャライザーでシンプルに表示してみましょう。
イニシャライザー
Map(coordinateRegion: Binding<MKCoordinateRegion>)
coordinateRegion: Binding
前述の MKCoordinateRegion の状態変数(@State or @Published)をバインディング指定します。
使用例
struct ContentView: View {
@State private var region =
MKCoordinateRegion(
center: .init(latitude: 35.710263046992736, longitude: 139.81067894034084),
latitudinalMeters: 300,
longitudinalMeters: 300
)
var body: some View {
Map(coordinateRegion: $region)
.edgesIgnoringSafeArea(.all)
}
}
ちなみに余談ですが、.edgesIgnoringSafeArea(.all) で全画面表示ができます。
(4) 複雑な指定方法
複雑、と言っても引数が多いだけで難しい内容ではありません。先ずは3種類のイニシャライザーを確認してみましょう。
① Map(coordinateRegion: Binding<MKCoordinateRegion>, annotationItems: RandomAccessCollection, annotationContent: (Identifiable) -> MapAnnotationProtocol)
② Map(coordinateRegion: Binding<MKCoordinateRegion>, interactionModes: MapInteractionModes, showsUserLocation: Bool, userTrackingMode: Binding<MapUserTrackingMode>?)
③ Map(coordinateRegion: Binding<MKCoordinateRegion>, interactionModes: MapInteractionModes, showsUserLocation: Bool, userTrackingMode: Binding<MapUserTrackingMode>?, annotationItems: RandomAccessCollection, annotationContent: (Identifiable) -> MapAnnotationProtocol)
1) coordinateRegion: Binding
MKCoordinateRegion の状態変数(@State or @Published)をバインディング指定します。
2) interactionModes: MapInteractionModes
ユーザー操作の許可を以下の3つから設定します。
- .pan スワイプ(ドラッグ)による操作を許可します。
- .zoom ダブルタッチ or ピンチ操作による拡大・縮小の操作を許可します。
- .all .pan と .zoom の両方を許可します。
3) showsUserLocation: Bool
true でユーザーの現在位置を表示します。
4) userTrackingMode: Binding?
マップがユーザーの現在位置を追跡させるどうかを状態変数で管理します。
- .follow ユーザーを追跡します。
- .none ユーザーの追跡を停止します。
指定例)
@State private var userTrackingMode: MapUserTrackingMode = .follow
Map(..., userTrackingMode: $userTrackingMode, ...)
5) annotationItems: RandomAccessCollection
所謂「ピン」の配列を渡します。ピンは Identifiable に準拠した構造体で定義し、CLLocationCoordinate2D 型の緯度経度を持たせます。
指定例)
struct PinItem: Identifiable {
let id = UUID()
let coordinate: CLLocationCoordinate2D
}
Map(...,
annotationItems: [
PinItem(coordinate: .init(latitude: 35.710263046992736, longitude: 139.81067894034084)),
PinItem(coordinate: .init(latitude: 35.700263046992736, longitude: 139.80067894034084))
],
...
)
6) annotationContent: (Identifiable) -> MapAnnotationProtocol
5) のピンの見た目(View)を以下の2種類のどちらかで表示します。
- MapMarker
- MapPin
指定例)
annotationContent: { item in
MapMarker(coordinate: item.coordinate)
}
または
annotationContent: { item in
MapPin(coordinate: item.coordinate)
}
(5) 複雑な指定の表示例
最後に引数が多いバージョンの表示例を紹介します。
struct ContentView: View {
@State private var region = MKCoordinateRegion(center: .init(latitude: 35.710263046992736, longitude: 139.81067894034084), latitudinalMeters: 300, longitudinalMeters: 300)
@State private var userTrackingMode: MapUserTrackingMode = .follow
struct PinItem: Identifiable {
let id = UUID()
let coordinate: CLLocationCoordinate2D
}
var body: some View {
Map(coordinateRegion: $region,
interactionModes: .zoom,
showsUserLocation: true,
userTrackingMode: $userTrackingMode,
annotationItems: [
PinItem(coordinate: .init(latitude: 35.710263046992736, longitude: 139.81067894034084)),
PinItem(coordinate: .init(latitude: 35.710063046992736, longitude: 139.81047894034084))
],
annotationContent: { item in
MapMarker(coordinate: item.coordinate)
}
).edgesIgnoringSafeArea(.all)
}
}
以上、ご参考になれば幸いです。
コメントを残す