Search code examples
swiftuigrid

SwiftUI GridRow height


Is there a way to have variable GridRow heights in a Grid? I am trying to draw a horizontal line between grid rows, and it's taking up the entire height of the common grid row.

See the picture below. I would like the red line to be immediately (1 pixel) below first row and immediately above 2nd row:

enter image description here

Here is my code:

import SwiftUI

struct ContentView: View {
    var body: some View {
        Grid {
            GridRow {
                Text("Column 1")
                Text("Column 2")
            }
            GridRow {
                GeometryReader { g in
                    Path { x in
                        x.move(to: .zero)
                        x.addLine(to: CGPoint(x: g.size.width,y: 0))
                    }.stroke(Color.red, lineWidth: 1).frame(height: 1)
                }
            }.gridCellColumns(2).gridCellUnsizedAxes(.vertical)
            GridRow {
                Text("Row 1 value 1")
                Text("Row 1 value 2")
            }
            GridRow {
                Text("Row 2 value 1")
                Text("Row 2 value 2")
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}


Solution

  • Grid row heights are automatically determined by their contents' height, so you don't actually need to set them explicitly.

    The extra space you see here are actually the vertical spacing between rows. The default spacing behaviour is that there should be little space between Texts, and more space between Text and non-Text views.

    You can override the default spacing behaviour by passing the verticalSpacing: argument.

    Grid(verticalSpacing: 0) {
        ...
    }
    

    You can then individually adjust each row's spacing by adding padding, e.g. .padding(.bottom, 20).

    Also note that rather than using a Path, I'd prefer drawing a very thin Rectangle:

    Rectangle()
        .fill()
        .foregroundColor(.red)
        .frame(height: 1)
    

    Or a Divider with an overlay:

    Divider()
        .overlay(Color.red)