📍

SwiftUIでGoogleMap上に現在地を表示する

2022/06/06に公開

SwiftUIでGoogleMapを表示する の続き


現在地を使うための設定

公式ドキュメントのRequesting location permission を参考に Info.plistPrivacy -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について、以下の記事が大変参考になりました
https://qiita.com/maiyama18/items/e36608af7e39f81af01c

次は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
https://github.com/mimimi-miOmi-mimi/ios_google_map_demo

Discussion