如何在 SwiftUI 的视图中调用方法

Pao*_*ini 2 google-maps-sdk-ios swiftui

刚刚开始使用 SwiftUI。

我有一个GoogleMapsViewContentView 使用CLLocationManager中我捕获事件AppDelegateSceneDelegate类与扩展它们的方式CLLocationManagerDelegate

如何在GoogleMapsViewfromAppDelegate或 中调用方法SceneDelegate

在这种情况下,我想.animate在通过 将位置更改事件发送到AppDelegate实例时调用该方法CLLocationManagerDelegate,但问题确实更通用。

zgl*_*uis 5

我制作并实现了CLLocationManager和MKMapView,它和maps几乎一样,希望对你有帮助:

简短回答:声明 a@Binding var foo: Any您将能够在每次 foo 更改时在 GoogleMapView 中进行更改,在这种情况下,foo 是您的位置,因此您可以在每次 foo 更新时调用 animate。

长答案

首先,我创建了一个符合 UIViewRepresentable 协议的 Mapview,就像您所做的那样,但是添加了一个 @Binding 变量,这是我的“触发器”。

地图视图

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我将我的 MapView 放在我的 ContentView 中,传递一个位置参数,我将在下面解释:

内容视图

struct ContentView: View {

    @ObservedObject var viewModel: ContentViewModel

    var body: some View {
        VStack {
            MapView(location: self.$viewModel.location)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的 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)
    }
}
Run Code Online (Sandbox Code Playgroud)

最后是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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)