Marcy
Marcy

Reputation: 6009

Dynamically change order of SwiftUI's VStack

How can the order of a VStack be changed during runtime? For HStack, the layout direction can be changed from .leftToRight and .rightToLeft. With ZStack, a zIndex can be adjusted to change order of the views, front to back. Is there something that can be used to change the order of a VStack? In my project, reversing the order top-to-bottom would work.

This is a greatly simplified example with duplication:

struct ContentView: View {
    @State var shouldFlip = false

    var body: some View {
        if shouldFlip {
            VStack {
                Color(.red)
                Color(.blue)
                Color(.yellow)
                Color(.green)
            }
        } else {
            VStack {
                Color(.green)
                Color(.yellow)
                Color(.blue)
                Color(.red)
            }
        }
    }
}

To avoid duplication is there anything like the following but for a VStack with .topToBottom and .bottomToTop:

struct ContentView: View {
    @State var shouldFlip = true
    
    var body: some View {
        HStack {
            Color(.red)
            Color(.blue)
            Color(.yellow)
            Color(.green)
        }.environment(\.layoutDirection, shouldFlip ? .rightToLeft : .leftToRight)
    }
}

Upvotes: 3

Views: 1588

Answers (1)

timbre timbre
timbre timbre

Reputation: 13970

I would start from opposite end: have underlying data ordered in proper way, and use ForEach to show it in the order it is stored. That way view itself doesn't need to know anything about the order:

struct ContentView: View {
    
    @State var shouldFlip = true
    
    var items: [Color] = [.red, .blue, .yellow, .green]

    var shownItems: [Color] {
        shouldFlip ? items.reversed() : items
    }

    var body: some View {
        VStack {
            ForEach(shownItems) { item in
                item
            }
        }
    }
}

In this case to make example fully compilable, I also need to make Color Identifiable:

extension Color: Identifiable {
    public var id: UUID {
        return UUID()
    }
}

but depending on what you actually want to display, this may not be needed if what you have is already Identifiable.

This way you have the logic (order of items) fully separated and independent from the way you want them displayed: today you want VStack, tomorrow you support rotation, and maybe want HStack in landscape view... Both will work the same way with pre-arranged data.

Also I wouldn't recommend using .rightToLeft - it's not for your use case, it's for right-to-left languages support (Hebrew, Arabic)

Upvotes: 5

Related Questions