Search code examples
iosswiftuimkmapview

Dismiss a map view (MKMapView) in SwiftUI


In a little iOS app using SwiftUI. There is a map and a button which is meant to dismiss the map.

I first read this tutorial: Advanced MKMapView with SwiftUI to know how to handle MKMapView in SwiftUI, and it is working. Here is the code for the MapView: (Code almost entirely based on the tutorial mentioned above)

import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    @Binding var centerCoordinate: CLLocationCoordinate2D
    @Environment(\.presentationMode) var presentationMode

    func makeUIView(context: Context) -> MKMapView {
        let mapView = MKMapView()
        mapView.delegate = context.coordinator
        appLocalizeMap(mapView)
        return mapView
    }

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

    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, MKMapViewDelegate {
        var parent: MapView

        init(_ parent: MapView) {
            self.parent = parent
        }
    }

    // User added code.
    func appLocalizeMap(_ mapView: MKMapView) {
        let locatSide = 1000.0
        mapView.isRotateEnabled = false
        mapView.region = MKCoordinateRegion(center: centerCoordinate,
                                            latitudinalMeters: locatSide,   longitudinalMeters: locatSide)
    }

    func dismiss() { // Not currently working ...
        self.presentationMode.wrappedValue.dismiss()
    }
}

Then I need to set the button to dismiss the map. This is where I am in trouble.

Below is the code, where I show the map and I set a button on top of it. It looks fine, but only looks. Nothing is working. After searching the net and reading some more, I have the feeling I am not setting the button where I should be. Beside I don't know where (presumably in the code of MapView) I am supposed to have the code making the map disapear.

ZStack {
    MapView(centerCoordinate:
        Binding(get: {CLLocationCoordinate2D(
                            latitude: self.refSpot.userLatitude,
                            longitude: self.refSpot.userLongitude)},
                set: {newValue in}))
        .edgesIgnoringSafeArea(.all)
    
    Button(action: {
        print("Dismiss Map")
    }) {
        VStack {
            HStack {
                Image(uiImage: UIImage(named: "Back.png")!)
                    .font(.title)
                    .foregroundColor(.gray)
                Spacer()
            }
            Spacer()
        }
    }
}

What I have found in other documents relative to dimissing a View doesn't seem to apply to the MapView here. Any relevant tip will be very much appreciated.

To make things clearer if needed. Here is the app at start:

enter image description here

The button Open a map works as expected. When tapped it brings this:

enter image description here

The problem lies in the cross shaped button at the top left of this last picture. This button should make the map and itself disappear, going back to the first image.

Using this code (modified):

Button(action: {self.showingMap.toggle()}) {
    Text("Open a map")
        .font(.largeTitle)
        .foregroundColor(.gray)
        .padding()
    .overlay(
        RoundedRectangle(cornerRadius: 30)
            .stroke(Color.gray, lineWidth: 4))
}.sheet(isPresented: $showingMap) {
    ZStack {
        if self.showMap {
            MapView(centerCoordinate:
                Binding(get: {CLLocationCoordinate2D(
                                latitude: self.refSpot.userLatitude,
                                longitude: self.refSpot.userLongitude)},
                        set: {newValue in}))
                .edgesIgnoringSafeArea(.all)
        }
        
        Button(action: {
            self.showMap.toggle()
        }) {
            VStack {
                HStack {
                    Image(uiImage: UIImage(named: "Back.png")!)
                        .font(.title)
                        .foregroundColor(.gray)
                    Spacer()
                }
                Spacer()
            }
        }
    }
}

Hitting the cross button now brings this view:

enter image description here

Where though the map itself is gone, the cross button is still there and the top image is not coming back.


Solution

  • I assume you meant this...

    struct DemoView: View {
        @State private var showMap = true
    
        var body: some View {
            ZStack {
                if showMap {
                    MapView(centerCoordinate:
                                Binding(get: {CLLocationCoordinate2D(
                                            latitude: self.refSpot.userLatitude,
                                            longitude: self.refSpot.userLongitude)},
                                        set: {newValue in}))
                        .edgesIgnoringSafeArea(.all)
                }
    
                Button(action: {
                    self.showMap.toggle()
                }) {
                    VStack {
                        HStack {
                            Image(uiImage: UIImage(named: "Back.png")!)
                                .font(.title)
                                .foregroundColor(.gray)
                            Spacer()
                        }
                        Spacer()
                    }
                }
            }
        }
    }