Xcode 12.3 | SwiftUI 2.0 | Swift 5.3
I have multiple HStack
whose first element must have the same width, but I cannot know how to achieve this.
HStack {
Text("Label 1:")
Text("Random texts")
}
HStack {
Text("Label 2 Other Size:")
Text("Random texts")
Text("Additional text")
}
HStack {
Text("Label 3 Other Larger Size:")
Text("Random texts")
}
This will display this:
Label 1: Random Texts
Label 2 Other Size: Random Texts Additional Text
Label 3 Other Larger Size: Random Texts
And I want to display this without using VStacks
, because each HStack
is a List Row
:
Label 1: Random Texts
Label 2 Other Size: Random Texts Additional Text
Label 3 Other Larger Size: Random Texts
[__________________________] [_____________...
same size
I tried using a @propertyWrapper
that stores the GeometryProxy
of each Label's background
and calcs the max WrappedValue
in order to set the .frame(maxWidth: value)
of each Label
, but without success, I cannot have working that propertyWrapper (I get a loop and crash).
struct SomeView: View {
@MaxWidth var maxWidth
var body: some View {
HStack {
Text("Label 1:")
.storeGeo($maxWidth)
.frame(maxWidth: _maxWidth.wrappedValue)
Text("Random texts")
}
HStack {
Text("Label 2 Larger Size:")
.storeGeo($maxWidth)
.frame(maxWidth: _maxWidth.wrappedValue)
// Continue as the example above...
...
...
3
Answers
Balanced widths between views
Based on all responses I coded a simpler way to get this working with a modifier.
First, we have to add the necessary extensions with the view modifier and the width getter:
Usage
With this, all the work is done. In order to get equal widths between views all we have to do is mark each view with the
balancedWidth
modifier and store the shared width value in a@State
variable with initial value ==.zero
:Sample
We can create more relationships between views and balance the widths between them separately by creating more than one
@State
variable.You can pass a GeometryReader width into any child view by using a standard var (not @State var).
Try this code out, its using GeometryReader and a list of Identifiable items which are passed a "labelWidth" they all render the same width for all labels. Note: I used a VStack in the row so it looked better, didn’t follow why a row can’t have a VStack in it.
The easiest way would be to set a specific .frame(width:) for the first Text() within the HStack. You can then use .minimumScaleFactor() to resize the text within to avoid the words being cut off. Here’s an example to get you started:
Result: