How do I make all views the same height in a SwiftUI View with an HStack?

Viewed 490

I want a simple graph with a colored rectangle of variable height for each data point. The white space below the colored rectangle should expand so that the bottom numbers line up, the way the top row of numbers does.

This is my view:

enter image description here

So I would like an idiomatic solution to getting the bottom row of numbers to line up with the 59. Any advice that points me in the right direction is welcome. Thanks.

Here's what I have so far:

struct DemoView: View {
    var dataSource = [1, 0, 34, 12, 59, 44]
    /// Provide a Dynamic Height Based on the Tallest View in the Row
    @State private var height: CGFloat = .zero // < calculable height
    /// The main view is a row of variable height views
    var body: some View {
        HStack(alignment: .top) {
            Spacer()
            /// i want these to all be the same height
            ForEach(0 ..< 6) { index in
                VStack {
                    Text("\(index)")
               Rectangle()
                   .fill(Color.orange)
                   .frame(width: 20, height: CGFloat(self.dataSource[index]))
                Text("\(dataSource[index])")
                }
           }
            Spacer()
        }
        .alignmentGuide(.top, computeValue: { d in
                DispatchQueue.main.async {
                    self.height = max(d.height, self.height)
                }
                return d[.top]
            })
    }
}

struct Demo_Preview: PreviewProvider {
    static var previews: some View {
        DemoView()
    }
}

Edit to show the final results:

I made the changes Asperi suggested, changed the .top alignments to .bottom and got a very nice simple chart:

enter image description here

1 Answers

Here is possible (seems simplest) approach. Tested with Xcode 12 / iOS 14

demo

struct DemoView: View {
    var dataSource = [1, 0, 34, 12, 59, 44]

    var body: some View {
        HStack(alignment: .top) {
            Spacer()
            /// i want these to all be the same height
            ForEach(0 ..< 6) { index in
                VStack {
                    Text("\(index)")
                    Color.clear
                        .frame(width: 20, height: CGFloat(dataSource.max() ?? 0))
                        .overlay(
                            Color.orange
                                .frame(height: CGFloat(self.dataSource[index]))
                        , alignment: .top)
                    Text("\(dataSource[index])")
                }
            }
            Spacer()
        }
    }
}
Related