SwiftUI animating expand and collapse of list rows

后端 未结 3 1945
被撕碎了的回忆
被撕碎了的回忆 2021-02-06 00:39

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 table

相关标签:
3条回答
  • 2021-02-06 00:51

    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)").onTapGesture {
                            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
        }
    }
    
    0 讨论(0)
  • 2021-02-06 01:07

    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)
        }
    }
    
    0 讨论(0)
  • 2021-02-06 01:09

    Thanks to Aakash Jaiswal's answer I was able to expand upon this implementation to suit my need to expand to three tiers, i.e., Section, Subsection, and Lesson. The compiler failed to compile the whole implementation in a single View, which is why I separated it out.

    import SwiftUI
    
    struct MenuView: View {
        var body: some View {
            HStack {
                List {
                    ToggleableMenuItemsView(sections: menuItems)
                    .padding()
                }
            }
            .background(Color("Gray"))
            .cornerRadius(30)
            .padding(.top, 30)
            .padding(.trailing, bounds.width * 0.2)
            .padding(.bottom, 30)
            .shadow(radius: 10)
        }
    
        @State var menuItemState = [String: Bool]()
        private var bounds: CGRect { UIScreen.main.bounds }
    
        private func isExpanded(_ menuItem: MenuItem) -> Bool {
            menuItemState[menuItem.id] ?? false
        }
    }
    
    struct ToggleableMenuItemsView: View {
        let sections: [MenuItem]
    
        var body: some View {
            ForEach(sections) { section in
                Section(
                    header: Text(section.title)
                        .font(.title)
                        .onTapGesture { self.menuItemState[section.id] = !self.isExpanded(section) },
                    content: {
                        if self.isExpanded(section) {
                            ForEach(section.children) { subsection in
                                Section(
                                    header: Text(subsection.title)
                                        .font(.headline)
                                        .onTapGesture { self.menuItemState[subsection.id] = !self.isExpanded(subsection) },
                                    content: {
                                        if self.isExpanded(subsection) {
                                            LessonsListView(lessons: subsection.children)
                                        }
                                    }
                                )
                            }
                        }
                    }
                )
            }
        }
    
        @State var menuItemState = [String: Bool]()
    
        private func isExpanded(_ menuItem: MenuItem) -> Bool {
            menuItemState[menuItem.id] ?? false
        }
    }
    
    struct LessonsListView: View {
        let lessons: [MenuItem]
    
        var body: some View {
            ForEach(lessons) { lesson in
                Text(lesson.title)
                    .font(.subheadline)
            }
        }
    }
    
    class MenuItem: Identifiable {
        var id: String
        let title: String
        var children: [MenuItem]
    
        init(id: String, title: String, children: [MenuItem] = []) {
            self.id = id
            self.title = title
            self.children = children
        }
    }
    
    let menuItems = [
        MenuItem(
            id: "01",
            title: "The Land in its World",
            children: [
                MenuItem(
                    id: "01A",
                    title: "North and South",
                    children: [
                        MenuItem(
                            id: "01A01",
                            title: "Between Continents"
                        ),
                        MenuItem(
                            id: "01A02",
                            title: "The Wet North"
                        ),
                        MenuItem(
                            id: "01A03",
                            title: "The Dry South"
                        ),
                        MenuItem(
                            id: "01A04",
                            title: "Between Wet and Dry"
                        )
                    ]
                ),
                MenuItem(
                    id: "01B",
                    title: "East and West",
                    children: [
                        MenuItem(
                            id: "01B01",
                            title: "Sea and Desert"
                        ),
                        MenuItem(
                            id: "01B02",
                            title: "Exchange in Aram"
                        ),
                        MenuItem(
                            id: "01B03",
                            title: "Exchange in Egypt"
                        ),
                        MenuItem(
                            id: "01B04",
                            title: "A Bypass Between"
                        )
                    ]
                ),
                MenuItem(
                    id: "01C",
                    title: "Between Empires",
                    children: [
                        MenuItem(
                            id: "01C01",
                            title: "Imperial Dreams"
                        ),
                        MenuItem(
                            id: "01C02",
                            title: "Egypt Marches"
                        ),
                        MenuItem(
                            id: "01C03",
                            title: "Taking Egypt's Wealth"
                        ),
                        MenuItem(
                            id: "01C04",
                            title: "The Land Between"
                        )
                    ]
                )
            ]
        )
    ]
    
    struct MenuView_Previews: PreviewProvider {
        static var previews: some View {
            MenuView()
        }
    }
    

    Here's a demo

    0 讨论(0)
提交回复
热议问题