如何在 SwiftUI 的视图中调用方法 [英] How to invoke a method in a view in SwiftUI

查看:31
本文介绍了如何在 SwiftUI 的视图中调用方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

刚刚开始使用 SwiftUI.

我在 ContentView 中有一个 GoogleMapsView使用 CLLocationManager 我通过使用 CLLocationManagerDelegate 扩展它们来捕获 AppDelegateSceneDelegate 类中的事件.>

如何从 AppDelegateSceneDelegate 调用 GoogleMapsView 中的方法?

在这个实例中,当位置更改事件通过 CLLocationManagerDelegate 发送到 AppDelegate 实例时,我想调用 .animate 方法,但问题确实更笼统.

解决方案

CLLocationManager和MKMapView的制作和实现,和map差不多,希望对你有帮助:

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

长答案:

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

地图视图:

struct MapView: UIViewRepresentable {@Binding var location: CLLocation//创建一个@Binding 变量,保持我想要放置视图的位置,每次更改时都会调用updateUIView私人让zoomMeters = 400func makeUIView(context: UIViewRepresentableContext) ->MKMapView {让 mapView = MKMapView(frame: UIScreen.main.bounds)返回地图视图}func updateUIView(_ mapView: MKMapView, context: Context) {//当位置改变时,调用updateUIView,所以这里我移动了地图:让 region = MKCoordinateRegion(center: location.coordinate,latitudinalMeters:CLLocationDistance(确切地说:zoomMeters)!,纵向米:CLLocationDistance(确切地说:zoomMeters)!)mapView.setRegion(mapView.regionThatFits(区域),动画:真)}}

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

内容视图:

struct ContentView: 查看 {@ObservedObject var viewModel: ContentViewModelvar主体:一些视图{虚拟堆栈{MapView(位置:self.$viewModel.location)}}}

在我的 ViewModel 中,我使用委托处理位置更改,以下是注释中包含更多详细信息的代码:

class ContentViewModel: ObservableObject {//location 是一个 Published 值,所以每次位置改变时都会更新视图@Published var 位置:CLLocation = CLLocation.init()//LocationWorker 将负责 CLLocationManager...让 locationWorker: LocationWorker = LocationWorker()在里面() {locationWorker.delegate = self}}扩展 ContentViewModel: LocationWorkerDelegate {func locationChanged(lastLocation: CLLocation?) {//位置改变了,我改变了self.location的值,它是一个@Published值所以它会刷新MapView内部的@Binding变量并调用MapView.updateUIViewself.location = CLLocation.init(latitude: lastLocation!.coordinate.latitude, longitude: lastLocation!.coordinate.latitude)}}

最后是LocationWorker,它负责CLLocationManager():

class LocationWorker: NSObject, ObservableObject {私人让 locationManager = CLLocationManager()var 委托:LocationWorkerDelegate?let objectWillChange = PassthroughSubject()@Published var locationStatus:CLAuthorizationStatus?{将设置{objectWillChange.send()}}@Published var lastLocation:CLLocation?{将设置{objectWillChange.send()}}覆盖初始化(){超级初始化()self.locationManager.delegate = self//...}}协议 LocationWorkerDelegate {func locationChanged(lastLocation: CLLocation?)}扩展 LocationWorker: CLLocationManagerDelegate {func locationManager(_ manager: CLLocationManager, didUpdateLocations 位置: [CLLocation]) {守卫让位置=locations.last else { return }self.lastLocation = 位置//当位置改变时:我使用我的委托 ->如果委托 != nil {委托!.locationChanged(lastLocation: lastLocation)}}}

Just getting started with SwiftUI.

I have a GoogleMapsView in a ContentView using the CLLocationManager I capture events in the AppDelegate or SceneDelegate class by means of extending them with CLLocationManagerDelegate.

How can I invoke a method in the GoogleMapsView from the AppDelegate or SceneDelegate?

In this instance I want to call the .animate method when the location change event is sent to the AppDelegate instance via the CLLocationManagerDelegate, but the question is really more generic.

解决方案

I made and implementation of CLLocationManager and MKMapView and it is almost the same as maps, hope it will help you:

Short answer: declaring a @Binding var foo: Any you will be able to make changes inside GoogleMapView every time that foo changes, in this case foo is your location, so you can call animate every time foo is updated.

Long answer:

First I created a Mapview that conforms UIViewRepresentable protocol, just as you did, but adding a @Binding variable, this is my "trigger".

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)
    }
}

Then I placed my MapView in my ContentView, passing a location argument, which I will explain next:

ContentView:

struct ContentView: View {

    @ObservedObject var viewModel: ContentViewModel

    var body: some View {
        VStack {
            MapView(location: self.$viewModel.location)
        }
    }
}

In my ViewModel, I handle location changes using a delegate, here is the code with more details in comments:

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)
    }
}

And finally here is LocationWorker which take cares of 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)
        }
    }
}

这篇关于如何在 SwiftUI 的视图中调用方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆