Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 434
aheze Avatar asked Sep 09 '25 18:09

aheze


1 Answers

Found a solution a year later, and it's really simple — just add .scaleEffect(1)!

.clipped() /// prevent the green view from overflowing
.scaleEffect(1) /// the magic modifier!

This is a much cleaner solution that doesn't involve setting custom frames or whatever. Also, it works with if and switch statements!

Yellow container moves right and left along with the green inner view, which also fades in and out.

I'm not completely sure why .scaleEffect(1) works, but it has something to do with how SwiftUI composes views. I think the modifier makes SwiftUI render it as a new group? If anyone knows why, I'd appreciate an answer.

Here's the full 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)
        .clipped() /// 1.
        .scaleEffect(1) /// 2.
        .offset(x: showingSubview ? 150 : 0, y: 0)
    }
}
like image 136
aheze Avatar answered Sep 12 '25 08:09

aheze