2

I wanted to create a list (without using List view) of attributes. Each attribute is a HStack which contains two texts, name and value. I want the name text to have always 30% of the width of the whole HStack and the value text to use the rest of the horizontal space. The height of each attribute depends on the content.

I try to accomplish it by having a following view:

struct FatherList: View {
    let attributes: Attributes
    
    init(_ attributes: Attributes) {
        self.attributes = attributes
    }
    
    var body: some View {
        VStack(spacing: CGFloat.spacing.medium) {
            ForEach(
                attributes,
                id: \.name,
                content: ChildView.init
            )
        }
    }
}

which contains the following ChildView:

struct ChildView: View {
    let listItem: Product.Attribute
    
    init(_ attribute: Product.Attribute) {
        self.attribute = attribute
    }
    
    var body: some View {
        GeometryReader { geometry in
            HStack(alignment: .top, spacing: 0) {
                Text(attribute.name)
                    .bold()
                    .frame(width: 0.3 * geometry.size.width)
                    .background(Color.yellow)
                Text(attribute.value)
            }
            .fixedSize(horizontal: false, vertical: true)
            .background(Color.red)
        }
    }
}

And the result I get is this:

enter image description here

The child views overlap which is not what I want, I want the child views to expand and follow each other. I am using geometryReader to accomplish the relative width that I described above. What am I doing wrong?

1 Answers1

4

Here is a demo of possible solution. Tested with Xcode 11.4 / iOS 13.4

demo

Note: ViewHeightKey is taken from this another my solution

struct ChildView: View {
    let attribute: Attribute

    @State private var fitHeight = CGFloat.zero

    var body: some View {
        GeometryReader { geometry in
            HStack(alignment: .top, spacing: 0) {
                Text(self.attribute.name)
                    .bold()
                    .frame(width: 0.3 * geometry.size.width, alignment: .leading)
                    .background(Color.yellow)
                Text(self.attribute.value)
                    .fixedSize(horizontal: false, vertical: true)
                    .frame(width: 0.7 * geometry.size.width, alignment: .leading)
            }
            .background(Color.red)
            .background(GeometryReader {
                Color.clear.preference(key: ViewHeightKey.self,
                    value: $0.frame(in: .local).size.height) })
        }
        .onPreferenceChange(ViewHeightKey.self) { self.fitHeight = $0 }
        .frame(height: fitHeight)
    }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • 1
    Thank you! That solved the problem! I also had to add ```.fixedSize(horizontal: false, vertical: true)``` to the Text(self.attribute.name), as I wanted also to resize vertically to content of the name too. – Danny Richard Aboo Jul 21 '20 at 11:38