Search code examples
arraysswiftsortingswiftuizstack

How to reverse SwiftUI ZStack order?


trying to recreate a next/previous item on a stack of cards. I have my cards in a ZStack. The problem I’m having is that by default ZStack are in reverse order (first item in array is at the bottom of the stack).

Here’s what the code looks like at the moment:

The Data

var userData: [User] = [
    User(id: 0, firstName: "Cindy", lastName: "Jones", age: 23, mutualFriends: 4, imageName: "image1", occupation: "Coach"),
    User(id: 1, firstName: "Mark", lastName: "Bennett", age: 27, mutualFriends: 0, imageName: "image2", occupation: "Insurance Agent"),
    User(id: 2, firstName: "Clayton", lastName: "Delaney", age: 20, mutualFriends: 1, imageName: "image23, occupation: "Food Scientist"),
]

Content View (where the data gets passed in)

CardsView(users: userData).tab(title: "Tinder Cards", image: "music.note")

The Card Stack

struct CardStack: View {
  @State var users: [User]

  var body: some View {
    ZStack {
      ForEach(self.users, id: \.self) { user in
        if user.id > self.maxID - 4 { //only show 4 at a time
          CardView(user: user)
        }
      }
    }
  }
} 

At the moment, I can think of 2 ways to solve this:

  1. Reverse the order of the array.
  2. Change the zIndex on individual cards.

Because the array is already in the correct order for all other screens, the first option seems like a bad idea (and maybe slow if there are a lot of cards). That said I’ve tried passing the data into the view with CardsView(users: userData.reversed()) and it seems to have no effect.

The second option is to change the zIndex on individual cards. In this example, every User has an Int as an ID, so I thought I could just negate it like this, but it doesn’t have any effect:

ZStack {
  ForEach(self.users, id: \.self) { user in
    if user.id > self.maxID - 4 {
      CardView(user: user)
        .zIndex(Double(user.id) * -1)
    }
  }
}

And, curiously, if I change the id’s to be negative when they array is created like User(id: -1, they’re not visible at all. Does anyone have any ideas or know what I’m getting/doing wrong here?

Thanks :3


Solution

  • import SwiftUI
    
    struct ReverseZView: View {
        let values: [Int] = [0,1,2,3,4,5,6,7,8,9]
        let colors: [Color] = [.red,.yellow,.orange,.green,.blue,.gray,.black]
        var body: some View {
            VStack{
                ZStack{
                    ForEach(Array(values.enumerated()), id:\.offset, content: { (index, value) in
                        Circle()
                            .overlay(Text(value.description).foregroundColor(.white))
                            .frame(width: 40)
                            .foregroundColor(colors.randomElement()!)
                        //use the index to find the opposite value
                            .zIndex(Double(values.count - index))
                    })
                }
                ZStack{
                    ForEach(Array(values.enumerated()), id:\.offset, content: { (index, value) in
                        Circle()
                            .overlay(Text(value.description).foregroundColor(.white))
                            .frame(width: 40)
                            .foregroundColor(colors.randomElement()!)
                        //Just making the index negative should also reverse
                            .zIndex(-Double(index))
                    })
                }
                
            }
        }
    }