So I just need the views within an HSTack
to each take the entire width available to them so the space is evenly distributed and all have the same width.
As for height, they should also all have the same height regardless of text length.
Current code:
struct TestViewHStack: View {
let strings = ["Short", "some long text", "short"]
var body: some View {
HStack {
ForEach(strings, id: .self) { title in
CardView(title: title)
.frame(maxWidth: .infinity)
}
}
}
}
struct CardView: View {
let title: String
var body: some View {
VStack(spacing: 8) {
Image(systemName: "star.fill")
.resizable()
.frame(width: 20, height: 20)
Text(title)
.font(.subheadline)
}
.padding(16)
.background(Color.white)
.clipShape(RoundedRectangle(cornerRadius: 16))
.shadow(color: .gray.opacity(0.2), radius: 8, x: 0, y: 2)
}
}
Output:
I thought setting .frame(maxWidth: .infinity)
would make it each take the entire width available, but it doesnt seem to do that. Also tried messing with frames and fixedSize()
modifiers but wasnt able to achieve the desired result.
Thanks!
2
Answers
For the width:
They already have the same width, but you cant see it because you apply the height after setting the background. So reorder the modifiers to make it visible:
Visible Equal Widths Demo:
For the height:
If you just need a fixed height, just add a
maxHeight
to the frame and control the height of the stack.But it seems like you don’t know the height and you need all items to have the same size with the tallest one. So you need to let them size themselves and update anyone with the shorter height. This is where
onPreferenceChange
comes in and requires some work.Note that you must first size and then apply the background. So You need to rearrange your UI logic
For the width, you were doing it the right way by using
maxWidth: .infinity
, except that this needs to be applied before the background and other decorations (like shadow and clip shape). So:.frame
modifier fromTestViewHStack
toCardView
CardView
toTestViewHStack
.The first way involves less changes (but see the note after the screenshot below).
For the height, I would suggest one of the following two techniques:
maxHeight: .infinity
to have all the cards expand to this height, perhaps usingalignment: .top
:If you are concerned that moving
maxWidth: .infinity
intoCardView
stops it from being re-usable then you could always makemaxWidth
a parameter of typeCGFloat?
too, in the same way asmaxHeight
has been parameterised above. You could also support a default ofnil
, so that it behaves in the same way as you had it before.