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.
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) {}
}