スマホ アプリ の強みとして「 地図 の表示」や 「場所に ピン を立てること」 が挙げられると思います。 SwiftUI を用いて実装できる 地図 サービス には いくつかの種類がありますが 本記事では Apple 純正の Map を取り上げ、 SwiftUI を用いて 以下を実装する方法について説明していきます。
- 緯度経度情報を基に 地図 を表示する方法
- 1 つの ピン を立てる方法
- 複数 ピン を立てる方法
Xcode: 13.1 iOS: 14.5 Swift: 5
緯度経度を基に 地図 を表示
まずはじめに 緯度経度を基に地図を表示してみたいと思います。 Apple Developer サイト の情報 に従って Apple Park の地図を表示してみます。
- MapKit を インポート
- @State 変数 として MKCoordinateRegion 型の変数 region を作成
- MKCoordinateRegion は 以下を引数にもつ
引数 | 説明 |
---|---|
center | 中心地点を CLLocationCoordinate2D を 緯度経度 を基に指定 |
latitudinalMeters | 地図に表示する 南北方向の広さを メートル で指定 |
longitudinalMeters | 地図に表示する 東西方向の広さを メートル で指定 |
- Map オブジェクト には 上述した region 変数を引数に指定
import MapKit struct AppleParkMap: View { @State private var region = MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 37.334_900, longitude: -122.009_020), latitudinalMeters: 750, longitudinalMeters: 750 ) var body: some View { Map(coordinateRegion: $region) } }
ContentView で この View (AppleParkMap) を呼び出す形にして ビルド してみると以下のような結果となります。 コード 上は 東西 南北 共に 750 m としていますが、縦長の画面に表示するため、 南北 750 m として表示されます。
なお 以下のように 東西方向 50 m とすると、東西 50 m の地図が表示されます。 指定した サイズ を 表示領域に最大限表示するようなかたちになっています。
@State private var region = MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 37.334_900, longitude: -122.009_020), latitudinalMeters: 750, longitudinalMeters: 50 )
地図上 に ピン を追加
続いて、 先程作成した地図に Apple Developer サイト の情報を参考に ピン を追加してみたいと思います。
Annotation Items の定義
Map に対して annotationItems として、 以下のように定義した MapAnnotationProtocol 型で Map ピン を指定する必要があります。 init() の中に記載された通り、 引数に 緯度, 経度 の数値を指定することで MapAnnotationProtocol 型を生成することができます。
struct IdentifiablePlace: Identifiable { let id: UUID let location: CLLocationCoordinate2D init(id: UUID = UUID(), lat: Double, long: Double) { self.id = id self.location = CLLocationCoordinate2D( latitude: lat, longitude: long) } }
Annotation Items を引数に指定し Map に ピン を追加
上記を annotationItems 引数に追加するように 先程の View を以下のように修正します。
struct AppleParkMap: View { let place: IdentifiablePlace @State private var region = MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 37.334_900, longitude: -122.009_020), latitudinalMeters: 750, longitudinalMeters: 750 ) var body: some View { Map(coordinateRegion: $region, annotationItems: [place]) { place in MapPin(coordinate: place.location, tint: Color.purple) } } }
同時に ContentView からの呼び出し方法も修正していきます。 先程の例では AppleParkMap View には引数が不要でしたが、 今回は Apple Park の緯度, 経度 を指定することで Apple Park に ピン を立てたいと思います。
struct ContentView: View { var body: some View { AppleParkMap(place: IdentifiablePlace(lat: 37.334_900, long: -122.009_020)) } }
ピン を 追加した Map
以下の通り Apple Park に 紫色の ピン を立てることができました。
Map に ピン を複数 追加
本記事の最後に 地図上に ピン を複数 追加する方法を紹介します。 今まで作成してきた Apple Park を中心とした地図に 以下 2つ の ピン を 追加してみたいと思います。
- Steve Jobs Theater
- Apple Park Tantau Reception
ピン の 緯度, 経度 定義
以下のように MapAnnotationProtocol 型 として定義した IdentifiablePlace オブジェクト として 今回追加するピンの情報を登録します。
@State private var places: [IdentifiablePlace] = [ // Steve Jobs Theater IdentifiablePlace(lat: 37.331_01, long: -122.007_45), // Apple Park Tantau Reception IdentifiablePlace(lat: 37.332_44, long: -122.006_14) ]
なお、緯度経度 情報は Google Map 上で右クリックするなどで 以下のように知ることができます。
Map 描画部分実装
Map 描画部分は 以下のような引数を用います。
引数 | 説明 |
---|---|
coordinateRegion | MKCoordinateRegion で指定した 緯度経度地点 と その範囲 |
annotationItems | annotation として表示する アイテム ここでは 緯度経度情報を含む IdentifiablePlace オブジェクト の配列 |
annotationContent | クロージャー としてannotation アイテム を生成する処理 |
AppleParkMap の body を以下のように修正します。 今回は ピン の色を赤にしてみます。
var body: some View { Map(coordinateRegion: $region, annotationItems: places, annotationContent: { place in MapPin(coordinate: place.location, tint: Color.red) } ) }
複数 ピン を追加した Map
ビルド すると 以下のように 2 つの場所に ピン が追加された地図が表示されます。
まとめ
- MapKit をインポートし Map を利用可能に
- 地図は CLLocationCoordinate2D で中心地点を決め、 あわせて 表示範囲を メートル で指定
- ピン を立てるときは MapAnnotationProtocol 型 で ピン の位置を定義
- ピン を複数立てるときは Map の 引数として以下を指定
- annotationItems: 立てたい ピン の位置情報を MapAnnotationProtocol 型 で 配列として定義
- annotationContent: クロージャー の中で MapPin 生成処理 を記述
関連記事
参照情報
Apple Developer Site
How do I add pins and other annota…
サンプルコード ( SwiftUI )
1 つの ピン を Map に表示するサンプル
// // ContentView.swift // import SwiftUI struct ContentView: View { var body: some View { AppleParkMap(place: IdentifiablePlace(lat: 37.334_900, long: -122.009_020)) } }
// // AppleParkMap.swift // import SwiftUI import MapKit struct IdentifiablePlace: Identifiable { let id: UUID let location: CLLocationCoordinate2D init(id: UUID = UUID(), lat: Double, long: Double) { self.id = id self.location = CLLocationCoordinate2D( latitude: lat, longitude: long) } } struct AppleParkMap: View { let place: IdentifiablePlace @State private var region = MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 37.334_900, longitude: -122.009_020), latitudinalMeters: 750, longitudinalMeters: 750 ) var body: some View { Map(coordinateRegion: $region, annotationItems: [place]) { place in MapPin(coordinate: place.location, tint: Color.purple) } } }
複数 ピン を Map に表示するサンプル
// // ContentView.swift // import SwiftUI struct ContentView: View { var body: some View { AppleParkMap() } }
// // AppleParkMap.swift // import SwiftUI import MapKit struct IdentifiablePlace: Identifiable { let id: UUID let location: CLLocationCoordinate2D init(id: UUID = UUID(), lat: Double, long: Double) { self.id = id self.location = CLLocationCoordinate2D( latitude: lat, longitude: long) } } struct AppleParkMap: View { @State private var places: [IdentifiablePlace] = [ // Steve Jobs Theater IdentifiablePlace(lat: 37.330_93, long: -122.007_46), // Apple Park Tantau Reception IdentifiablePlace(lat: 37.332_44, long: -122.006_14) ] @State private var region = MKCoordinateRegion( center: CLLocationCoordinate2D(latitude: 37.334_900, longitude: -122.009_020), latitudinalMeters: 750, longitudinalMeters: 750 ) var body: some View { Map(coordinateRegion: $region, annotationItems: places, annotationContent: { place in MapPin(coordinate: place.location, tint: Color.red) } ) } }