matchedGeometryEffect does not animate smoothly

Viewed 535

I am trying to do a simple matchedGeometryEffect and it's not working. I've got a simple Image that has a fixed frame and I want to animate it to an Image that takes up the whole screen. This is how it looks like right now, as you can see, it doesn't transition smoothly:

enter image description here

This is my code:

struct ContentView: View {
    @State private var enlarged = false
    @Namespace private var animation
    
    var body: some View {
        ZStack {
            if (enlarged) {
                Image("dunes")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .matchedGeometryEffect(id: "image", in: animation)
                    .ignoresSafeArea(.all, edges: .all)
            } else {
                Image("dunes")
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .matchedGeometryEffect(id: "image", in: animation)
                    .frame(width: 300, height: 225)

            }
        }
        .onTapGesture {
            withAnimation {
                enlarged.toggle()
            }
        }
    }
}
1 Answers

To make matchedGeometryEffect animate smoothly, you have few rules to follow. You have to declare the frame after the matchedGeometryEffect. The animation has to be placed at the end of each image, instead of having it inside the .tapGesture.

Here is the code with the modifications:

struct ContentView: View {

  @State private var enlarged = false
  @Namespace private var namespace

  var body: some View {
    ZStack {
      if enlarged {
        Image("dunes")
          .resizable()
          .matchedGeometryEffect(id: "image", in: namespace)
          .aspectRatio(contentMode: .fill)
          .ignoresSafeArea(.all, edges: .all)
          .animation(.easeInOut)
      }
      else {
        Image("dunes")
          .resizable()
          .matchedGeometryEffect(id: "image", in: namespace)
          .aspectRatio(contentMode: .fill)
          .frame(width: 300, height: 225)
          .animation(.easeInOut)

      }
    }
    .onTapGesture { enlarged.toggle() }
  }
}
Related