Я сделал и реализацию CLLocationManager и MKMapView, и она почти такая же, как карты, надеюсь, это поможет вам:
Краткий ответ : объявив @Binding var foo: Any
, вы сможете вносить изменения в GoogleMapView каждый раз, когда меняется foo, в этом случае foo - ваше местоположение, поэтому вы можете вызывать animate при каждом обновлении foo.
Длинный ответ :
Сначала я создал Mapview, который соответствует протоколу UIViewRepresentable, как и вы, но добавив переменную @Binding, это мой " триггер ".
MapView :
struct MapView: UIViewRepresentable {
@Binding var location: CLLocation // Create a @Binding variable that keeps the location where I want to place the view, every time it changes updateUIView will be called
private let zoomMeters = 400
func makeUIView(context: UIViewRepresentableContext<MapView>) -> MKMapView {
let mapView = MKMapView(frame: UIScreen.main.bounds)
return mapView
}
func updateUIView(_ mapView: MKMapView, context: Context) {
//When location changes, updateUIView is called, so here I move the map:
let region = MKCoordinateRegion(center: location.coordinate,
latitudinalMeters: CLLocationDistance(exactly: zoomMeters)!,
longitudinalMeters: CLLocationDistance(exactly: zoomMeters)!)
mapView.setRegion(mapView.regionThatFits(region), animated: true)
}
}
Затем я поместил свой MapView в мой ContentView, передав аргумент местоположения, который я объясню следующим образом:
ContentView :
struct ContentView: View {
@ObservedObject var viewModel: ContentViewModel
var body: some View {
VStack {
MapView(location: self.$viewModel.location)
}
}
}
В моей ViewModel я обрабатываю изменения местоположения с помощью делегата, вот код с более подробной информацией в комментариях:
class ContentViewModel: ObservableObject {
//location is a Published value, so the view is updated every time location changes
@Published var location: CLLocation = CLLocation.init()
//LocationWorker will take care of CLLocationManager...
let locationWorker: LocationWorker = LocationWorker()
init() {
locationWorker.delegate = self
}
}
extension ContentViewModel: LocationWorkerDelegate {
func locationChanged(lastLocation: CLLocation?) {
//Location changed, I change the value of self.location, it is a @Published value so it will refresh the @Binding variable inside MapView and call MapView.updateUIView
self.location = CLLocation.init(latitude: lastLocation!.coordinate.latitude, longitude: lastLocation!.coordinate.latitude)
}
}
И, наконец, LocationWorker, который заботится о CLLocationManager ():
class LocationWorker: NSObject, ObservableObject {
private let locationManager = CLLocationManager()
var delegate: LocationWorkerDelegate?
let objectWillChange = PassthroughSubject<Void, Never>()
@Published var locationStatus: CLAuthorizationStatus? {
willSet {
objectWillChange.send()
}
}
@Published var lastLocation: CLLocation? {
willSet {
objectWillChange.send()
}
}
override init() {
super.init()
self.locationManager.delegate = self
//...
}
}
protocol LocationWorkerDelegate {
func locationChanged(lastLocation: CLLocation?)
}
extension LocationWorker: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
self.lastLocation = location
//When location changes: I use my delegate ->
if delegate != nil {
delegate!.locationChanged(lastLocation: lastLocation)
}
}
}