Home > Back-end >  SwiftUI - ExpandableView inside VStack
SwiftUI - ExpandableView inside VStack

Time:04-09

I'm trying to have multiple expandable views with animation inside a VStack. I have the following code:

struct ContentView: View {
    var body: some View {
        NavigationView {
            ScrollView {
                VStack {
                    ExpandableView(headerTitle: "First")
                    ExpandableView(headerTitle: "Second")
                    Spacer()
                }
            }
        }
    }
}

And the ExpandableView:

struct ExpandableView: View {
    let headerTitle: String
    @State private var collapsed: Bool = true
    
    var body: some View {
        Button(
            action: {
                self.collapsed.toggle()
            },
            label: {
                VStack(spacing: 2) {
                    ZStack {
                        Rectangle()
                            .fill(.gray)
                        VStack {
                            Text("\(headerTitle) Header")
                            if !collapsed {
                                HStack {
                                    Text("Text A")
                                    Text("Text B")
                                }
                            }
                        }
                    }
                    .frame(height: collapsed ? 52 : 80)
                    ZStack(alignment: .top) {
                        Rectangle()
                            .fill(.gray)
                            .frame(height: 204)
                        VStack {
                            Text("Content A")
                            Text("Content B")
                            Text("Content C")
                        }
                    }
                    .frame(maxHeight: collapsed ? 0 : .none)
                    .clipped()
                }
            }
        )
        .buttonStyle(PlainButtonStyle())
        .animation(.easeOut, value: collapsed)
    }
}

The result is this: enter image description here

As you can see if I open the last expandableView is opens correctly. However if I open the first one when the second is closed, it actually opens the second. It only opens correctly the first one if the second is already open. It seems the VStack is not rendering correctly itself. Any ideas why this happening? Thanks for the help.

CodePudding user response:

I migth be the way the buttons works. Here is a cleaner solution:

struct ExpandableView: View {
        let headerTitle: String
        @State private var collapsed: Bool = true
        
        var body: some View {
            
            VStack(spacing: 2) {
                
                Button(
                    action: {
                        withAnimation(.easeOut){
                            self.collapsed.toggle()
                        }
                    },
                    label: {
                        
                        VStack {
                            Text("\(headerTitle) Header")
                            if !collapsed {
                                HStack {
                                    Text("Text A")
                                    Text("Text B")
                                }
                            }
                        }.frame(maxWidth: .infinity)
                    })
                .buttonStyle(.borderedProminent)
                .tint(.gray)
                
                if(!self.collapsed) {
                    VStack {
                        Divider().background(.black)
                        Text("Content A")
                        Text("Content B")
                        Text("Content C")
                    }
                }
                Spacer()
            }
            .frame(height: collapsed ? 52 : 204)
            .frame(maxWidth: .infinity)
            .background(.gray)
            .padding()
        }
    }
  • Related