SwiftUI - Animate view transition and position change at the same time

Viewed 3110

I have a yellow container with a green view inside. I want to move the container while also hiding/showing the inner green view, with an animation. Currently, I'm using .offset for the movement, and an if statement for the green view's transition.

The problem is, although the yellow container moves, the green view does not. It simply fades in and out at the destination offset. I want it to also move alongside the yellow container.

This is what I get currently This is what I want
Yellow container moves right and left while the green inner view fades in and out. The green view stays on the right side Yellow container moves right and left along with the green inner view, which also fades in and out.

Here's my code:

struct ContentView: View {
    @State var showingSubview = false
    
    var body: some View {
        VStack {
            Button("Show Subview") {
                withAnimation(.easeInOut(duration: 2)) {
                    showingSubview.toggle()
                }
            }
            
            if showingSubview {
                Text("Subview")
                    .padding()
                    .background(Color.green)
            }
        }
        .padding()
        .background(Color.yellow)
        .offset(x: showingSubview ? 150 : 0, y: 0)
    }
}

How can I make the green view move along with the yellow container, as it fades in and out? Preferably, I'd like to keep using if or switch statements for the insertion/removal.

1 Answers

You can just change the height as it animates.

Code version #1

This will not fade and appears inside the yellow rectangle.

Code:

struct ContentView: View {
    @State var showingSubview = false

    var body: some View {
        VStack(spacing: 0) {
            Button("Show Subview") {
                withAnimation(.easeInOut(duration: 2)) {
                    showingSubview.toggle()
                }
            }

            Text("Subview")
                .padding()
                .background(Color.green)
                .padding(.top)
                .frame(height: showingSubview ? nil : 0, alignment: .top)
                .clipped()
        }
        .padding()
        .background(Color.yellow)
        .offset(x: showingSubview ? 150 : 0, y: 0)
    }
}

Result #1

Result 1

Code version #2

This version will fade out and appear at bottom edge, as your GIF shows.

Code:

struct ContentView: View {
    @State var showingSubview = false

    var body: some View {
        VStack(spacing: 0) {
            Button("Show Subview") {
                withAnimation(.easeInOut(duration: 2)) {
                    showingSubview.toggle()
                }
            }

            Text("Subview")
                .padding()
                .background(Color.green)
                .padding(.top)
                .frame(height: showingSubview ? nil : 0, alignment: .top)
                .padding(.bottom)
                .background(Color.yellow)
                .clipped()
                .opacity(showingSubview ? 1 : 0)
        }
        .padding([.horizontal, .top])
        .background(Color.yellow)
        .padding(.bottom)
        .offset(x: showingSubview ? 150 : 0, y: 0)
    }
}

Result #2

Result 2

Related