Marin
Marin

Reputation: 531

SwiftUI List Rows Different Heights for Different System Images

In my SwiftUI app, I have a List inside of a sidebar NavigationView with 2 rows, like this:

List {
    NavigationLink(destination: MyView1()) {
        Label("Test Row 1", systemImage: "list.bullet")
    }
    
    NavigationLink(destination: MyView2()) {
        Label("Test Row 2", systemImage: "shippingbox")
            .frame(maxWidth: .infinity, alignment: .leading)
    }
}

However the second row is taller that the first row, I believe due to the image. If I change the image to this:

NavigationLink(destination: MyView2()) {
    Label("Test Row 2", systemImage: "list.number")
        .frame(maxWidth: .infinity, alignment: .leading)
}

the rows are now the same height. I don't want to fix the height of the rows, but I was wondering if there was a solution where the rows could be the same height.

Upvotes: 0

Views: 855

Answers (1)

Yrb
Yrb

Reputation: 9695

If you want to ensure that the rows are even, you can use PreferenceKeys to set the row heights to the height of the tallest row like this:

struct EvenHeightListRow: View {
    
    @State var rowHeight = CGFloat.zero

    var body: some View {
        List {
            NavigationLink(destination: Text("MyView1")) {
                Label("Test Row 1)", systemImage: "list.bullet")
                    // This reads the height of the row
                    .background(GeometryReader { geometry in
                        Color.clear.preference(
                            key: HeightPreferenceKey.self,
                            value: geometry.size.height
                        )
                    })
                    .frame(height: rowHeight)
            }
            
            NavigationLink(destination: Text("MyView2")) {
                Label("Test Row 2)", systemImage: "shippingbox")
                    .background(GeometryReader { geometry in
                        Color.clear.preference(
                            key: HeightPreferenceKey.self,
                            value: geometry.size.height
                        )
                    })
                    .frame(height: rowHeight)
                    .frame(maxWidth: .infinity, alignment: .leading)
            }
        }
        // this sets backgroundSize to be the max value of the tallest row
        .onPreferenceChange(HeightPreferenceKey.self) {
            rowHeight = max($0, rowHeight)
        }
    }
}

// This is the actual preferenceKey that makes it work.
fileprivate struct HeightPreferenceKey: PreferenceKey {
    static var defaultValue: CGFloat = .zero
    static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {}
}

Upvotes: 1

Related Questions