2
votes

In a NavigationView I have a Button and a MKMapView (called MapView). When the user taps the button the map should zoom to the user's location.

I know how to make use of MKMapView.setRegion to zoom to the users's location, but I can't figure out how the correct way to make MapView aware that it should perform this action when the user taps the button.

If I somehow have a reference to my MapView object, I can call setRegion, but I realize that is imperative and now when I'm learning SwiftUI I try to think declaratively instead.

So I believe I should set a State variable of some type and make MapView listen to changes to that variable. But if I manage to do that, then MapView calling setRegion would be imperative anyway.

So I'm scratching my head here. What should I do?

struct ContentView: View {

    @State private var foo: Bool = false

    var body: some View {
        NavigationView {
            MapView()
                .navigationBarItems(trailing:
                    HStack {
                        Button(action: {
                            // zoom to user's location
                            self.foo.toggle()
                        }) {
                            Image(systemName: "location")
                        }
                })
        }
    }
}

struct MapView: UIViewRepresentable {

    @Binding var foo: Bool

    // if foo is changed, then call zoomToUserLocation()

    func zoomToUserLocation() {
        // ...
        mapView.setRegion(region, animated: true)
    }
}

2

2 Answers

0
votes

It is not clear where do you get region (or it is set), but on any such binding changed the updateUIView of representable is called, so would do the call there and make it asynchronous, like below

func updateUIView(_ uiView: MKMapView, context: Context) {
    // if needed make something conditional here on `foo`

    self.zoomToUserLocation()
}
0
votes

You could use the updateUIView method of UIViewRepresentable. I would it use like this:

struct MapView: UIViewRepresentable {

    @Binding var foo: Bool

    func updateUIView(_ uiView: MKMapView, context: Context) {

        if foo {
            self.zoomToUserLocation()
        }

    }

    func zoomToUserLocation() {
        // ...
        mapView.setRegion(region, animated: true)
    }
}

You can also make something conditional like Asperi said.