Is there a way to conditionally flip the order of an HStack's contents?

Viewed 222

I'm using an HStack to layout some elements in my view hierarchy. I'd love to be able to conditionally flip the order of the elements.

HStack {
  Text("Hello")
  Text("World")
}

The idea is that this will either be layouted as "Hello World" or "World Hello" depending on my view's state.

HStack itself doesn't provide any functionality for this, but it also appears to be pretty much impossible trying to pull this out of the view itself attempting to use other ViewBuilders, ForEach-based approaches, etc.

The only way I can resolve this is by actually specifying both layouts entirely, which is what I'm trying to avoid.

let isFlipped: Bool

HStack {
  if isFlipped {
    Text("World")
    Text("Hello")    
  } else {
    Text("Hello")
    Text("World")
  }
}
1 Answers

Here is possible generic approach for any pair of views in any container base on using ViewBuilder.

Tested with Xcode 12

enter image description here

struct TestHStackFlip: View {
    @State private var flipped = false
    var body: some View {
        VStack {
            HStack {
                FlipGroup(if: flipped) {
                    Text("Text1")
                    Text("Text2")
                }
            }.animation(.default)     // animatable
            Divider()
            Button("Flip") { self.flipped.toggle() }
        }
    }
}

@ViewBuilder
func FlipGroup<V1: View, V2: View>(if value: Bool,
                @ViewBuilder _ content: @escaping () -> TupleView<(V1, V2)>) -> some View {
    let pair = content()
    if value {
        TupleView((pair.value.1, pair.value.0))
    } else {
        TupleView((pair.value.0, pair.value.1))
    }
}
Related