SwiftUI animating expand and collapse of list rows

2019-07-09 23:12发布

I'm using SwiftUI to animate an expand and collapse in a list.

How can I get the height expansion of the section to animate smoothly like it would in UIKit with a tableview?

struct Rows: View {
    let rows = ["Row 1", "Row 2", "Row 3", "Row 4", "Row 5"]

    var body: some View {
        Section {
            ForEach(rows.identified(by: \.self)) { name in
                Text(name)
                    .lineLimit(nil)
            }
        }
    }
}

struct Header: View {

    @State var isExpanded: Bool = false

    var body: some View {

        VStack(alignment: .leading) {
            Button(action: {
                self.isExpanded.toggle()

            }) {
                Text(self.isExpanded ? "Collapse Me" : "Expand Me")
                    .font(.footnote)
            }

            if self.isExpanded {
                Rows().animation(.fluidSpring())
            }
        }
    }
}

struct ContentView : View {

    var body: some View {
        List(0...4) { _ in
            Header()
        }
    }
}

The animation seems to only apply to the text in the rows not the actual height or separator line growing to accommodate the new rows. The row text also seems to start animating from the very top of the row rather than where it appears in the view hierarchy. I need a smooth animation.

标签: swiftui
2条回答
时光不老,我们不散
2楼-- · 2019-07-09 23:52

I implemented it like this: (It is with proper animation)

struct ExpandCollapseList : View {
    @State var sectionState: [Int:Bool] = [:]

    var body: some View {
        NavigationView{
            List{
                ForEach(1...6){ section in
                    Section(header: Text("Section \(section)").tapAction {
                        self.sectionState[section] = !self.isExpanded(section)
                    }) {
                        if self.isExpanded(section){
                            ForEach(1...4){ row in
                                Text("Row \(row)")
                            }
                        }
                    }
                }
            }.navigationBarTitle(Text("Expand/Collapse List"))
            .listStyle(.grouped)
        }
    }

    func isExpanded(_ section:Int) -> Bool {
        sectionState[section] ?? false
    }
}
查看更多
虎瘦雄心在
3楼-- · 2019-07-10 00:08

try to implement it like this:

struct ContentView : View {

    @State var expanded:[Int:Bool] = [:]

    func isExpanded(_ id:Int) -> Bool {
        expanded[id] ?? false
    }

    var body: some View {
        NavigationView{
            List {
                ForEach(0...80) { section in
                    Section(header: CustomeHeader(name: "Section \(section)", color: Color.white).tapAction {
                        self.expanded[section] = !self.isExpanded(section)
                    }) {
                        if self.isExpanded(section) {
                            ForEach(0...30) { row in
                                Text("Row \(row)")
                            }
                        }
                    }
                }
            }
        }.navigationBarTitle(Text("Title"))
    }
}

struct CustomeHeader: View {
    let name: String
    let color: Color

    var body: some View {
        VStack {
            Spacer()
            HStack {
                Text(name)
                Spacer()
            }
            Spacer()
            Divider()
        }
        .padding(0)
            .background(color.relativeWidth(1.3))
            .frame(height: 50)
    }
}
查看更多
登录 后发表回答