WrappingHStack
WrappingHStack copied to clipboard
Item sizes are calculated incorrectly when WrappingHStack has modifiers that change the size of its elements
In the preview window you can add
.environment(\.sizeCategory, .accessibilityMedium)
to the modifier. This will emulate larger accessible fonts.
This will cause truncated views, like so
This is not completely accurate, the problem is with modifiers outside WrappingHStack only. To measure the elements, type erasure is performed and the element is removed from the View hierarchy. Which means that modifiers on elements above the WrappingHStack will be ignored (wich may result in wrong sizes). With the current implementation, having to compute the whole hierarchy each time probably would be too time consuming (also, I'm not sure how I would pull that off). Maybe changing the way the NewLine element works could fix that.
Workaround: Set all necessary modifiers + environment variables directly on the items within WrappingHStack.
For example, in the librarie's example, adding .environment(\.sizeCategory, .accessibilityLarge)
to the WrappingHStack
that acts like a ForEach:
WrappingHStack(1...9, id:\.self, alignment: alignment, spacing: spacing) {
Text("Item: \($0)")
.padding(.all, 12)
.background(RoundedRectangle(cornerRadius: 10).stroke())
}
.frame(width: 380)
.environment(\.sizeCategory, .accessibilityLarge)
will result in wrong sizes:
but if you set it on the item labels Text("Item: \($0)")
:
WrappingHStack(1...9, id:\.self, alignment: alignment, spacing: spacing) {
Text("Item: \($0)")
.padding(.all, 12)
.background(RoundedRectangle(cornerRadius: 10).stroke())
.environment(\.sizeCategory, .accessibilityLarge)
}
.frame(width: 380)
it will result in the correct sizes:
Another example where I encountered this problem:
WrappingHStack(lineSpacing: 10) {
Toggle("1", isOn: $filter.filterByPlayers[0])
Toggle("2", isOn: $filter.filterByPlayers[1])
Toggle("3", isOn: $filter.filterByPlayers[2])
Toggle("4", isOn: $filter.filterByPlayers[3])
Toggle("5", isOn: $filter.filterByPlayers[4])
Toggle("6", isOn: $filter.filterByPlayers[5])
}.toggleStyle(.button)
breaks after 4 (on iPhone 8 Plus size) while
WrappingHStack(lineSpacing: 10) {
Toggle("1", isOn: $filter.filterByPlayers[0]).toggleStyle(.button)
Toggle("2", isOn: $filter.filterByPlayers[1]).toggleStyle(.button)
Toggle("3", isOn: $filter.filterByPlayers[2]).toggleStyle(.button)
Toggle("4", isOn: $filter.filterByPlayers[3]).toggleStyle(.button)
Toggle("5", isOn: $filter.filterByPlayers[4]).toggleStyle(.button)
Toggle("6", isOn: $filter.filterByPlayers[5]).toggleStyle(.button)
}
correctly shows all 6 items in one row.
Another instance of probably the same issue.
@lieanquintos without code this doesnt really say much
To make a workaround for my case with a Toggle + Togglestyle, I added fixedSize to text as...
Text(myTextvar)
.fixedSize(horizontal: true, vertical: false)
I had to add padding to the WrappingHStack on the right to ensure correct wrapping.