How can I make my image transition smoothly with matchedGeometryEffect?

291 Views Asked by At

The text will transition smoothly from left to right. The image will also transition smoothly from left to right, however it decides to fade out/fade in. Because it is the exact same image, I want the image to stay solid and not transparent in the animation. Can this be accomplished? Or is this a flaw in matchedGeometryEffect?

struct MainView: View {
    @Namespace private var animation
    @State private var isFlipped = false
    
    var body: some View {
        HStack {
            if isFlipped {
                Text("text")
                    .font(.subheadline)
                    .matchedGeometryEffect(id: "title", in: animation)
                Image("Logo")
                    .matchedGeometryEffect(id: "icon", in: animation)
            } else {
                Image("Logo")
                    .matchedGeometryEffect(id: "icon", in: animation)
                Text("text")
                    .font(.subheadline)
                    .matchedGeometryEffect(id: "title", in: animation)
            }
        }
        .onTapGesture {
            withAnimation {
                isFlipped.toggle()
            }
        }
    }
}
1

There are 1 best solutions below

1
On

I was able to use a "hack" to make it work. Somehow using 'identity' will still ignore the transition falling back to its default fading the views in and out. Somehow telling the asymmetric to the exact same thing does work. Perhaps someone has a logical explanation for this, cause I don't.

extension AnyTransition {
    static var identityHack: AnyTransition {
        .asymmetric(insertion: .identity, removal: .identity)
    }
}

struct MainView: View {
    @Namespace private var animation
    @State private var isFlipped = false
    
    var body: some View {
        HStack {
            if isFlipped {
                Text("text")
                    .font(.subheadline)
                    .matchedGeometryEffect(id: "title", in: animation)
                Image("Logo")
                    .transition(.identityHack)
                    .matchedGeometryEffect(id: "icon", in: animation)
            } else {
                Image("Logo")
                    .transition(.identityHack)
                    .matchedGeometryEffect(id: "icon", in: animation)
                Text("text")
                    .font(.subheadline)
                    .matchedGeometryEffect(id: "title", in: animation)
            }
        }
        .onTapGesture {
            withAnimation {
                isFlipped.toggle()
            }
        }
    }
}