Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use match geometry effect when navigating between views using a navigation link

My home view contains a CustomView that opens a detailed view via a NavigationLink when tapped. The detailed view also contains the CustomView, just in a different location.

Can I use the match geometry effect to transition/animate the location of the CustomView when the navigation link is clicked?

struct HomeView: View {
    @Namespace var namespace
    
    var body: some View {
        NavigationStack {
            VStack {
                Text("Top")
                NavigationLink {
                    DetailView(namespace: namespace)
                } label: {
                    CustomView()
                        .matchedGeometryEffect(id: "testId", in: namespace)
                }
                Text("Bottom")
            }
        }
    }
}
struct DetailView: View {
    var namespace: Namespace.ID
    
    var body: some View {
        VStack {
            CustomView()
                .matchedGeometryEffect(id: "testId", in: namespace)
            Text("Details")
            Spacer()
        }
    }
}
like image 484
cabyambo Avatar asked Mar 01 '26 17:03

cabyambo


1 Answers

I'm going to say, "no, you can't use .matchedGeometryEffect to animate the position of a view across a NavigationStack transition."

Some details: first of all, the .matchedGeometryEffect will not work without an animation block. So you could rewrite your code to something like this:

struct HomeView: View {
    @Namespace var namespace
    @State private var showDetail = false
    
    var body: some View {
        NavigationStack {
            VStack {
                Text("Top")
                Button {
                    withAnimation() {
                        showDetail.toggle()
                    }
                } label: {
                    CustomView
                        .matchedGeometryEffect(id: "testId", in: namespace)
                }
                Text("Bottom")
            }
            .navigationDestination(isPresented: $showDetail) {
                DetailView(namespace: namespace)
            }
        }
    }
}

private struct DetailView: View {
    var namespace: Namespace.ID
    
    var body: some View {
        VStack {
            CustomView()
                .matchedGeometryEffect(id: "testId", in: namespace)
            Text("Details")
            Spacer()
        }
    }
}

This gives you an opportunity to use withAnimation in a way that matchedGeometryEffect requires. However, you still don't get the animation you want, leading me to the conclusion above.

I would speculate that Navigation transitions are different from normal SwiftUI transitions. A clue supporting this is that any .transition you could apply to the things in DetailView do not trigger during transition. Another clue is that using withAnimation(.easeIn(duration: 5)) does not give you a 5 second transition.

Your best bet might be to not use NavigationStack. Just use a conditional (with animated transition) to switch between the two layouts. I would also recommend you spend a few days studying the excellent resources on the Swift UI Lab site, with this being a particularly relevant page for you.

I hope that helps!

like image 139
Curious Jorge Avatar answered Mar 03 '26 17:03

Curious Jorge



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!