swiftswiftuiswiftui-listcardviewstackview

Vertical card stack view in SwiftUI


I want to make a card stack view vertically and it's overlapping with the associated card.

Like:
enter image description here

I tried with my example code but didn't work. Something missing out in the offset parameter. Please save my time.

Sample code:

// A card stack view that shows the data for Restaurant
struct CardStackView: View {
    // static data
    let restaurants = [
        Restaurant(name: "Joe's Original"),
        Restaurant(name: "The Real Joe's Original"),
        Restaurant(name: "Original Joe's")
    ]
    
    var body: some View {
        ScrollView {
            LazyVStack() {
                ForEach(restaurants.indices) { index in
                    CardView(restaurant: restaurants[index], index: index)
                }
            }
        }
    }
}

// Data struct
struct Restaurant: Identifiable {
    let id = UUID()
    let name: String
}

// Card View
struct CardView: View {
    var restaurant: Restaurant
    var index: Int
    
    let color: [Color] = [.blue, .red, .yellow]
    
    var body: some View {
       
        ZStack(){
            color[index%3]
                .cornerRadius(10.0)
                .padding(.trailing)
                .offset(y: 20.0)
            
            Text("Come and eat at \(restaurant.name)")
                .padding(EdgeInsets(top: 20, leading: 20, bottom: 30, trailing: 20))
                .foregroundColor(.white)
        }
    }
}

Solution

  • Set offset to ZStack

    struct CardView: View {
        var restaurant: Restaurant
        var index: Int
        
        let color: [Color] = [.blue, .red, .yellow]
        
        var body: some View {
            ZStack{
                color[index%3]
                    .cornerRadius(10.0)
                Text("Come and eat at \(restaurant.name)")
                    .padding(EdgeInsets(top: 20, leading: 20, bottom: 30, trailing: 20))
                    .foregroundColor(.white)
            }.offset(y: index == 0 ? 0 : CGFloat(-25 * index))
        }
    }
    
    

    If you want the same size for all cards then pass the last index and set padding.

    Here is the demo.

    struct CardStackView: View {
        // static data
        let restaurants = [
            Restaurant(name: "Joe's Original"),
            Restaurant(name: "The Real Joe's Original"),
            Restaurant(name: "Original Joe's")
        ]
        
        var body: some View {
            ScrollView {
                LazyVStack(spacing: 0) { //<=== Here
                    ForEach(restaurants.indices) { index in
                        CardView(restaurant: restaurants[index], index: index, isLast: index == restaurants.count - 1) //<=== Here
                    }
                }
            }
        }
    }
    
    // Card View
    struct CardView: View {
        var restaurant: Restaurant
        var index: Int
        var isLast: Bool
        
        let color: [Color] = [.blue, .red, .yellow]
        
        var body: some View {
            ZStack{
                color[index%3]
                    .cornerRadius(10.0)
                Text("Come and eat at \(restaurant.name)")
                    .padding(EdgeInsets(top: 20, leading: 20, bottom: isLast ? 20 : 30, trailing: 20)) //<=== Here
                    .foregroundColor(.white)
            }.offset(y: index == 0 ? 0 : CGFloat(-10 * index))
        }
    }
    
    

    enter image description here