How can I animate individual rows in SwiftUI List?

Viewed 2178

I want to show a List, where each row appears with an opacity animation and with an increasing delay. So 1st row should appear after 0.1 seconds, second after 0.3 seconds, third after 0.5 seconds etc.

I tried the following, but it does not work, as all rows appear at once and without animation.

Any tips would be much appreciated!

struct GuideListView: View {

    @State var showListItems = false
    @State var animationDelay = 0.1
    // definitions of viewRouter, data etc.

    var body: some View {

        VStack {

            // other items, navLink etc.

            List {
                
                ForEach(data) { item in
                    
                    Button(action: {
                        // navigation action
                    }, label: {
                        RowView(item: item)
                    })
                    .opacity(showListItems ? 1 : 0)
                    .animation(Animation.easeOut(duration: 0.6).delay(animationDelay), value: showListItems)
                    .onAppear{
                        animationDelay = animationDelay + 0.2
                    }

                } //: ForEach
          
            } //: List

        } //: VStack
        .onAppear{
            showListItems = true
    }
}
1 Answers

The key seems to be using the indices from the ForEach loop to set the times at which the animations appear.

Below is the code. The toggle switch just resets the state to show the animation:

struct GuideListView: View {
    let data = ["One", "Two", "Three", "Four"]
    @State var showListItems = false
    @State var animationDelay = 0.5
    // definitions of viewRouter, data etc.
    
    var body: some View {
        
        VStack {
            
            // other items, navLink etc.
            Toggle("Show List Items", isOn: $showListItems)

            List {
                
                ForEach(data.indices) { index in
                    
                    Button(action: {
                        // navigation action
                    }, label: {
                        Text(data[index])
                    })
                        .opacity(showListItems ? 1 : 0)
                        .animation(Animation.easeOut(duration: 0.6).delay(animationDelay * Double(index)), value: showListItems)

                } //: ForEach
                
            } //: List
            
        } //: VStack
    }
}
Related