Item sizes are calculated incorrectly when WrappingHStack has modifiers that change the size of its elements
mylogon341 opened this issue · comments
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)
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)
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.
@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.