SwiftUI Images jumping with with dropdown view toggle

Viewed 44

I created a custom dropdown where when clicked a bottom view opens up. What I am observing is that during the open click the header images are jumping to center and then coming right back up:

Jumping images example

struct ListSample: View {
    
    var body: some View {
        List {
            Dropdown()
            Dropdown()
            Dropdown()
        }
    }
}

struct Dropdown: View {
    
    @State var showBox = false
    @State var rotateDeg = 0.0
    
    var body: some View {
        VStack {
            showHideBox
            VStack {
                if showBox {
                    Rectangle()
                        .frame(height: 200)
                }
            }
            Spacer()
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0)
        .clipped()
        .animation(.easeOut, value: showBox)
        .transition(.slide)
    }
    
    var showHideBox: some View {
        HStack {
            Image(systemName: "squareshape.split.2x2")
            Text(showBox ? "Hide Box" : "Show Box")
                .font(.caption)
            Spacer()
            Image(systemName: "chevron.right")
                .foregroundColor(.accentColor)
                .rotationEffect(.degrees(rotateDeg))
        }
        .onTapGesture {
            withAnimation {
                showBox.toggle()
                rotateDeg = showBox ? 90 : 0
            }
        }
        .padding(6)
    }
}

Not sure how to get around this because the text is staying in place, any suggestions would be helpful. Thank you.

1 Answers

It is because of default .center alignment in top VStack, use instead .top, so always visible part be always stuck to the top and removable just expands towards the buttom:

VStack {
    showHideBox
    VStack {
        if showBox {
            Rectangle()
                .frame(height: 200)
        }
    }
    Spacer()
}
.frame(maxWidth: .infinity, alignment: .top) // << here !!

*note: minWidth/minHeight are by-default 0, so can be removed from a modifier.

Related