How to align a MapView that ignores the safe area with the rest of my content with Swift UI?

Viewed 656

I am new to coding in Swift and just wanted to play around a bit. Therefore, I have tried my luck on this beginner series here: https://developer.apple.com/tutorials/swiftui/creating-and-combining-views

Problem:

I could finish the tutorial and it looked okay so far, but then I wanted to add a Divider between the MapView and the rest of the content. I run into a layouting problem. The MapView covers the whole top area as they said, but on iPhone 11 the layout adds a large gap between the MapView and the next Divider.

What I have tried so far:

I was playing around with the VStack spacing and the preview settings but could not make the gap disappear really, unless I removed the edgesIgnoreSafeArea() property that is.

Within the PreviewProvider I could set the Layout to sizeThatFits. This is how I want it to be rendered in the end, but not just in the preview.

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 0.0) {
            MapView()
                .frame(width: .infinity, height: 300.0)
                .edgesIgnoringSafeArea(.top) // this will ignore the top spacing
            
            Divider()
              .frame(height: 2)
              .background(Color.black)
            
            ImageMaskedView()
             .offset(y: -130.0)
             .padding(.bottom, -130)
            
            VStack(alignment: .leading) {
                Text("Turtle Rock")
                    .font(.title)
                
                HStack(alignment: .top) {
                    Text("Joshua Tree National Park")
                        .font(.subheadline)
                    Spacer()
                    Text("California")
                        .font(.subheadline)
                }
            }
            .padding(10)
            
            Spacer() // this will push the rest up
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .previewDevice("iPhone 11")
    }
}
import SwiftUI
import MapKit

struct MapView: UIViewRepresentable {
    func makeUIView(context: Context) -> MKMapView {
        MKMapView(frame: .zero)
    }
    
    func updateUIView(_ uiView: MKMapView, context: Context) {
        let coordinate = CLLocationCoordinate2D(latitude: 34.011286, longitude: -116.166868)
        let span = MKCoordinateSpan(latitudeDelta: 2.0, longitudeDelta: 2.0)
        let region = MKCoordinateRegion(center: coordinate, span: span)
        uiView.setRegion(region, animated: true)
    }
}

struct MapView_Previews: PreviewProvider {
    static var previews: some View {
        MapView()
    }
}

Left: iPhone 11 (huge gap between the map and the Divider), Right: Preview using sizeThatFits (correct) enter image description here

Question:

What do I have to adjust in order to make it work? Do I need another layout or do I have to set a fixed size for the whole content or what am I supposed to do? I just want the elements in the outermost layout to be as tight as possible and to apply paddings, offsets etc. later on the individual elements.

What am I missing?

1 Answers

You have to apply edgesIgnoringSafeArea before setting the frame height. If you first set height to 300.0 it will calculate the position of the element without the safe area and hence it will take more space, which creates the white space.

MapView()
    .edgesIgnoringSafeArea(.top) // this will ignore the top spacing
    .frame(height: 300.0)

enter image description here

Related