SwiftUIでGoogleMap上に現在地を表示する
現在地を使うための設定
公式ドキュメントのRequesting location permission を参考に Info.plist
に Privacy -Location When In Use Usage Description
を追加
(これは練習なので文言はそれらしいものを入れました)
地図上に現在地を表示する
おなじみのCLLocatonManager
を使います。
CLLocationManagerの処理を行うクラスを作成
Structは継承できないため、CLLocationManagerの処理を行うためのクラスCoordinator
を作成しいい感じの処理を適宜追加
struct MapView: UIViewRepresentable {
final class Coordinator: NSObject, CLLocationManagerDelegate {
var parent: MapView
init(mapView: MapView) {
parent = mapView
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let userLocation = locations.last else { return }
let camera = GMSCameraPosition.camera(
withLatitude: userLocation.coordinate.latitude,
longitude: userLocation.coordinate.longitude,
zoom: 15.0
)
parent.mapView.animate(to: camera)
parent.locationManager.stopUpdatingLocation()
}
}
...
...
現在地が更新されたらMapも動くようにする
MapView.swift
はさきほどのclassを使いながら以下のようにします。
struct MapView: UIViewRepresentable {
...
...
let mapView = GMSMapView(frame: .zero)
@State var locationManager = CLLocationManager()
func makeCoordinator() ->Coordinator {
return Coordinator(mapView: self)
}
func makeUIView(context: Context) -> GMSMapView {
mapView.isMyLocationEnabled = true
locationManager.delegate = context.coordinator
locationManager.requestWhenInUseAuthorization()
locationManager.distanceFilter = 50
locationManager.startUpdatingLocation()
return mapView
}
...
}
アプリを起動すると以下のようなダイアログが出てきて、現在地がいい感じに表示されるはずです…!
UIViewRepresentable・Coordinator
SwiftUIしょしんしゃ🔰、この2つが謎すぎる
https://developer.apple.com/documentation/swiftui/uiviewrepresentable には以下のようにある
A wrapper for a UIKit view that you use to integrate that view into your SwiftUI view hierarchy.
SwiftUIでUIKitを使えるようにしてくれる良い感じのやつらしい(雑な翻訳)
@interface GMSMapView : UIView
GMSMapViewのDefinitionをよく見てみるとUIViewを継承していることが分かります。
https://developer.apple.com/documentation/swiftui/uiviewrepresentable ではCoordinator
について以下の通り
The system doesn’t automatically communicate changes occurring within your view to other parts of your SwiftUI interface. When you want your view to coordinate with other SwiftUI views, you must provide a Coordinator instance to facilitate those interactions. For example, you use a coordinator to forward target-action and delegate messages from your view to any SwiftUI views.
ラップしたViewのActionやDelegateの処理をしたければ、Coordinatorを使えってコト…❕❔
完全に理解した
終わりに
UIViewRepresentable
について、以下の記事が大変参考になりました
次はMapを拡大縮小する(SDKにはないらしい)
参考
https://developers.google.com/maps/documentation/ios-sdk/current-place-tutorial
https://developer.apple.com/documentation/corelocation/cllocationmanager
https://kumano-te.com/activities/google-maps-sdk-swiftui
https://developer.apple.com/documentation/swiftui/uiviewrepresentable
https://qiita.com/maiyama18/items/e36608af7e39f81af01c
Discussion