0

I'm dealing with a very strange issue in SwiftUI. Basically, I'm trying to have a list of subviews (Collapsible(), in the code below), where each of these views can expand and collapse when tapped. Additionally, these views display one HStack for every item in the items state variable, and there's a button to add one additional item per tap. Each Collaspible() looks like this:

enter image description here

Now, I want to display these Collapsibles in a list. In the code below, I've just added three in a pretty straightforward manner:

struct ContentView: View {

    var body: some View {
        List {
            Collapsible()
            Collapsible()
            Collapsible()
        }
    }
}

That ends up looking like this:

enter image description here

Here's where the issue comes in. If I expand one of these collapsibles and add some items, this is what happens:

enter image description here

The list delegates extra room for the Collapsible(), even though when it is not expanded, the maxHeight is 0. Does anyone know why this is happening and how to avoid it?

Here's the code for the Collapsible() struct.

struct Collapsible: View {
    @State private var isExpanded: Bool = false
    @State private var items: [String] = ["item1", "item2", "item3"]
    
    var body: some View {
        VStack {
            HStack {
                Text("Tap Me")
                Spacer()
                Text("Info")
            }
            .contentShape(Rectangle())
            .onTapGesture {
                isExpanded.toggle()
            }
            
            VStack {
                ForEach(items, id: \.self) { item in
                    HStack {
                        Text("Item")
                        Spacer()
                        Text("Info")
                    }
                    .padding(.vertical, 5)
                }
                
                Button("Add Item") {
                    items.append("new item")
                }
            }
            .frame(maxHeight: isExpanded ? .none : 0)
            .clipped()
        }
        .background(Color.cyan)
    }
}
Nicolas Gimelli
  • 695
  • 7
  • 19

1 Answers1

1

It seems that it's the button that occupies the white space you're seeing; when tapping there, it'll continue to call the button's code.

I can't tell you how to solve this with the .frame() modifier, but I can offer an alternative: if

If you simply use an if condition to show/hide the views, it works as you'd expect it to:

if isExpanded {
    VStack {
        ForEach(items, id: \.self) { item in
            HStack {
                Text("Item")
                Spacer()
                Text("Info")
            }
            .padding(.vertical, 5)
        }
            
        Button("Add Item") {
            items.append("new item")
        }
    }
}

One additional problem is that adding items with the same value will also have the same identifier, though I assume this is just for the purpose of demonstrating the problem.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • Thanks Michael. The reason that I opted for the .frame() modifier is because eventually, I want to animate the view that appears when you tap to kind of "drop down" from the unexpanded view. Do you know how I could achieve that using the if statement? I've tried it before and the animation always seems very buggy, expanding from the middle outward, rather than from the top down. – Nicolas Gimelli Mar 21 '23 at 21:25
  • Have you tried it on a real device? On my iPhone it seems to animate the way you want it to. I haven't dabbled too much with animation, but when I need to I usually come back to this: https://developer.apple.com/tutorials/swiftui/animating-views-and-transitions (or sometimes an article on hackingwithswift.com) – Michael Brünen Mar 21 '23 at 21:31
  • I have, perhaps I'll make a separate post on that later today and I'll comment the link with the code so you can take a look. – Nicolas Gimelli Mar 21 '23 at 21:39
  • Here is the new question: https://stackoverflow.com/questions/75818815/swiftui-animating-expanding-views-from-the-top-downward – Nicolas Gimelli Mar 23 '23 at 02:35