Search code examples
swiftuiswiftui-layout

Why does adding a frame() to an image add padding in between the image and it's sibling?


Why does adding a frame() to an image add padding in between the image and it's sibling? E.g. why is there padding underneath the A, but not the B, in this example? Thank you!

enter image description here

struct ContentView: View {
    var body: some View {
        VStack {
            Text("A")
                .border(Color.red, width:1)
            Image(systemName: "globe")
                .frame(minHeight:50)
                .border(Color.black, width:1)
        }
        .border(Color.green, width:1)
        VStack {
            Text("B")
                .border(Color.red, width:1)
            Image(systemName: "globe")
                .border(Color.black, width:1)
        }
        .border(Color.green, width:1)

    }
}

Solution

  • I think this is because symbol images are treated like text by SwiftUI. Each symbol is a "glyph".

    Layout out

    VStack {
        Text("A")
        Image(systemName: "globe")
    }
    

    is a bit like laying out two lines of text (though not literally two lines, because lineSpacing doesn't have an effect on this). Because these are all text, the VStack tries to make it look like one whole "text block", and doesn't add extra space between them. That is how text is supposed to flow.

    Once you add a frame, the VStack doesn't see them as the same text block anymore, and adds the default spacing it normally adds between views. You can see this in effect when you add non-symbol images, or other non-text views:

    // this also adds default spacing
    VStack {
        Text("A")
        Rectangle().fill(.red)
    }
    
    // this too!
    VStack {
        Text("A")
        Image("some non-symbol image")
    }
    

    You can remove the default spacing by setting spacing: 0.