Home > Software design >  SwiftUI : animate row expand in List
SwiftUI : animate row expand in List

Time:08-22

I need to expand each row of a List with a smooth animation (from top to bottom). A row has a main text (always displayed) and a secondary text that is shown only when row is expanded.

Here is code for List:

struct ContentView: View {
    var body: some View {
        NavigationView {
            List {
                ForEach((1...3), id: \.self) { _ in
                    ItemRow()
                }
            }
            .navigationTitle("Demo")
            .navigationBarTitleDisplayMode(.inline)
        }
    }
}

And for ItemRow:

struct ItemRow: View {
    
    @State private var expanded = false
    
    var body: some View {
        VStack {
            HStack {
                Text("Hello world")
                
                Spacer()
                
                Image(systemName: "chevron.forward.circle")
                    .rotationEffect(.degrees(expanded ? 90 : 0))
                    .onTapGesture {
                        withAnimation() {
                            expanded.toggle()
                        }
                    }
            }
            
            if expanded {
                Text("Lorem ipsum dolor sit amet. Vel dicta error qui vero incidunt et fugit quisquam aut modi praesentium qui veritatis sed ipsam magnam. Ad iure velit ut possimus voluptatem cum dolores dicta. Ex cupiditate libero ut impedit internos aut reprehenderit molestias! Aut debitis dignissimos sit incidunt internos aut mollitia explicabo aut vitae numquam et repellendus iusto.")
                    .foregroundColor(.secondary)
                    .font(.caption)
                    .frame(height: expanded ? nil : 0)
                    .clipped()
            }
        }
    }
}

Rows expand when I tap on chevron button. But the animation is not smooth at all: the main text starts in center at first and moves on top of row. enter image description here


Since DiscloureButtonStyle is iOS 16 Beta only, here is a trick to show custom chevron (I don't recommend this approach btw):

struct ItemRow: View {
    @State private var expanded = false

    var body: some View {
        DisclosureGroup(isExpanded: $expanded) {
            Text("Lorem ipsum dolor sit amet. Vel dicta error qui vero incidunt et fugit quisquam aut modi praesentium qui veritatis sed ipsam magnam. Ad iure velit ut possimus voluptatem cum dolores dicta. Ex cupiditate libero ut impedit internos aut reprehenderit molestias! Aut debitis dignissimos sit incidunt internos aut mollitia explicabo aut vitae numquam et repellendus iusto.")
                .foregroundColor(.secondary)
                .font(.caption)
                .clipped()
        } label: {
            HStack {
                Text("Hello world")
                Spacer()
                Image(systemName: "chevron.forward.circle")
                    .rotationEffect(.degrees(expanded ? 90 : 0))
            }.padding(.trailing, -20) // <-- To use the space of the default one
        }.accentColor(.clear) // <-- To hide the default one

    }
}
  • Related