listanimationswiftuisections

SwiftUI animate list section rows


I try to add custom animation when list section show and hide its rows, the animation is when rows appear its will slide from top to bottom and when the section rows disappear the rows slide from bottom to top.

The code:

struct AnimateListRows: View {
    
    let rowValues = Array(0...10)
    @State private var showSection = false
    
    var body: some View {
        List {
            ForEach(rowValues, id: \.self) {
                    ListRow(rowValue: $0)
            }
            Section {
                if showSection {
                    ForEach(rowValues, id: \.self) {
                        ListRow(rowValue: $0)
                    }
                }
            } header: {
                HStack {
                    Text("Section")
                    Spacer()
                    Image(systemName: "button.programmable")
                        .foregroundColor(.blue)
                        .onTapGesture {
                            withAnimation(.easeIn(duration: 0.3)) {
                            showSection.toggle()
                            }
                        }
                }
            }
            ForEach(rowValues, id: \.self) {
                    ListRow(rowValue: $0)
            }
        }
    }
}

struct AnimateListRows_Previews: PreviewProvider {
    static var previews: some View {
        AnimateListRows()
    }
}

Solution

  • I tried your example with an iPhone 14 simulator using this dummy implementation of ListRow:

    struct ListRow: View {
        var rowValue: Int
        var body: some View {
            Text("\(rowValue)")
        }
    }
    

    The rows are revealed as you described. So I assume that you don't want this, instead you want some kind of custom transition which you have not described?

    My understanding is that List doesn't give you much control over transitions, but there may be some ways to work around this limitation:

        if showSection {
            List {
                ForEach(rowValues, id: \.self) {
                    ListRow(rowValue: $0)
                }
            }
            .transition(.move(edge: .trailing))
        }
    

    However, you'll need to find a different way to toggle the visibility, because the section header doesn't work well.