dkk / WrappingHStack

A SwiftUI HStack with the ability to wrap contained elements

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Item sizes are calculated incorrectly when WrappingHStack has modifiers that change the size of its elements

mylogon341 opened this issue · comments

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
Screenshot 2022-02-21 at 12 27 43 pm

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:
Screenshot 2022-03-05 at 10 12 43

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:
Screenshot 2022-03-05 at 10 09 48

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.
IMG_1F3D19D8E3E4-1

@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.