20210726のiOSに関する記事は1件です。

[SwiftUI]iOS14から用意されたMapを使って動的なMapを開発してみる

投稿の経緯 SwiftUIでMapを表示するにはこちらにもあるようにUIViewRepresentableを使ってカスタムViewを作成しなければなりませんでした。 しかし、iOS14からMapというSwiftUI用のViewが標準で搭載され、簡易的に実装することができるようになったので、個人開発中のアプリで使ってみたので、投稿します。 環境 Swift version 5.4.2 Xcode version 12.5.1 MapKitをインポート SwiftUIファイルを作成し(今回はMapView)、MapKitをインポートします。 import MapKit 必要な変数の準備 今回MapKitを扱うにあたって使用するイニシャライザはCLLocationCoordinate2DとMKCoordinateSpanです。なおこちら2点を扱うにあたってMKCoordinateRegionという状態変数が必要です。 各イニシャライザを要約して説明すると... CLLocationCoordinate2D 表示領域の中心位置を緯度経度で決める MKCoordinateSpan 緯度・経度それぞれに対する表示領域をそれぞれの縮尺(単位は度)で指定します。1度で約111kmあるそうなので比較的小さい値を指定することが多いと思います。例えば、100m を縮尺で表すと 0.0009 くらいになります。 また、引数として緯度経度を保存するDouble型の変数を用意します。 緯度 latitude 経度 longitude ?以下ここまでのコードです? import SwiftUI import MapKit struct MapView: View { @State private var region = MKCoordinateRegion() // 座標領域 var coordinate: CLLocationCoordinate2D? // 表示領域の中心位置 var latitude: Double // 緯度 var longitude: Double // 経度 /////以下省略///// } Mapを使ってマップを表示 続いてMapを使ってViewに反映させるので、まずはコードを見ていただきます。 Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $userTrackingMode, annotationItems: [ PinItem(coordinate: .init(latitude: latitude, longitude: longitude)) ], annotationContent: { item in MapMarker(coordinate: item.coordinate) }) 少し複雑に見えますが、難しくはないのでひとつひとつ解説します。 coordinateRegion MKCoordinateRegionの状態変数をバインディング指定します。(@State or @Published) interactionModes ユーザー操作の許可を以下の3つから設定します。 .pan スワイプ(ドラッグ)による操作を許可。 .zoom ダブルタッチ or ピンチ操作による拡大・縮小の操作を許可。 .all .pan と .zoom の両方を許可。 showsUserLocation trueでユーザーの現在位置を表示。 userTrackingMode マップがユーザーの現在位置を追跡させるどうかを状態変数で管理します。 .follow ユーザーを追跡します。 .none ユーザーの追跡を停止します。 以下のように状態変数を準備して、指定してあげれば良いです。 @State private var userTrackingMode: MapUserTrackingMode = .none annotationItems マップ上で表示するピンの位置を緯度経度で指定します。ピンはIdentifiableに準拠した構造体で定義し、CLLocationCoordinate2D型の緯度経度を管理させます。 struct PinItem: Identifiable { let id = UUID() let coordinate: CLLocationCoordinate2D } annotationContent annotationItemsのピンのデザインを決めます。MapMarker、MapPinの二択です。 ?以下ここまでのコードです? import SwiftUI import MapKit struct PinItem: Identifiable { let id = UUID() let coordinate: CLLocationCoordinate2D } struct MapView: View { @State private var region = MKCoordinateRegion() // 座標領域 @State private var userTrackingMode: MapUserTrackingMode = .none var coordinate: CLLocationCoordinate2D? // 表示領域の中心位置 var latitude: Double // 緯度 var longitude: Double // 経度 var body: some View { Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $userTrackingMode, annotationItems: [ PinItem(coordinate: .init(latitude: latitude, longitude: longitude)) ], annotationContent: { item in MapMarker(coordinate: item.coordinate) }) } } 引数で取得した緯度経度を使って表示領域の中心位置と縮尺を決める private func setRegion(coordinate: CLLocationCoordinate2D) { region = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 0.0009, longitudeDelta: 0.0009) ) } プライベートな関数を用意して引数にCLLocationCoordinate2Dを用意し、受け取った値は、状態変数regionのcenterに指定。(ここで表示領域の中心位置が決まる) 次に、spanにMKCoordinateSpanを指定し縮尺度合いを決定する。 そして、先ほど記述したMapに.onAppearを指定し、MapViewが呼ばれたら、まずsetRegionが呼ばれるように調整する。 ※.onAppearはswiftでいうviewDidAppearのような扱いです。 ?以下ここまでのコードです? import SwiftUI import MapKit struct PinItem: Identifiable { let id = UUID() let coordinate: CLLocationCoordinate2D } struct MapView: View { @State private var region = MKCoordinateRegion() // 座標領域 @State private var userTrackingMode: MapUserTrackingMode = .none var coordinate: CLLocationCoordinate2D? // 表示領域の中心位置 var latitude: Double // 緯度 var longitude: Double // 経度 var body: some View { Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, userTrackingMode: $userTrackingMode, annotationItems: [ PinItem(coordinate: .init(latitude: latitude, longitude: longitude)) ], annotationContent: { item in MapMarker(coordinate: item.coordinate) }) .onAppear { setRegion(coordinate: CLLocationCoordinate2D(latitude: latitude, longitude: longitude)) } } // 引数で取得した緯度経度を使って動的に表示領域の中心位置と、縮尺を決める private func setRegion(coordinate: CLLocationCoordinate2D) { region = MKCoordinateRegion(center: coordinate, span: MKCoordinateSpan(latitudeDelta: 0.0009, longitudeDelta: 0.0009) ) } } 別ファイルからMapViewを呼び出す MapView(latitude: <Double>, longitude: <Double>) となるので、latitudeに緯度を、longitudeに経度を指定してあげれば、MapViewの.onAppearが呼ばれ、setRegionの中で表示領域の中心位置と、縮尺が決定され、Viewが更新されます。 お知らせ 現在、iOS開発案件を業務委託で募集中です(副業)。TwitterDMでご依頼をお待ちしています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む