Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI: Matched Geometry Effect doesn't work

I am making app which is using Matched Geometry Effect. It is matching two rectangles embedded inside two different views. It isn't working as it supposed to. Please help me. Here is test view for that:

struct ContentViewTest: View {
    @State var details = false
    @Namespace var animation
    
    var body: some View {
        ZStack {
            if !details {
                TestView2(details: $details, anim: animation)
            }
            if details {
                TestView1(details: $details, anim: animation)
            }
        }
    }
}

Here is TestView1:

struct TestView1: View {
    @Binding var details: Bool
    var anim: Namespace.ID
    var body: some View {
        ZStack{
            Color.gray.ignoresSafeArea()
            Color.red.frame(width: 300, height: 700)
                .matchedGeometryEffect(id: "id1", in: anim)
                .onTapGesture {
                    withAnimation {
                        details = false
                    }
                }
        }
    }
}

And here is TestView2:

struct TestView2: View {
    @Binding var details: Bool
    var anim: Namespace.ID
    var body: some View {
        ZStack{
            Color.green.ignoresSafeArea()
            Color.red.frame(width: 200, height: 200)
                .matchedGeometryEffect(id: "id1", in: anim)
                .onTapGesture {
                    withAnimation {
                        details = true
                    }
                }
        }
    }
}
like image 445
green8 Avatar asked Sep 15 '25 17:09

green8


2 Answers

Just add properties position (in both matched views), like in below

Color.red.frame(width: 300, height: 700)
    .matchedGeometryEffect(id: "id1", in: anim, properties: .position)  // << here !!

or (depending on effect which you want to achieve) change order of modifiers (for both views), like

Color.red
    .matchedGeometryEffect(id: "id1", in: anim) // << here !! 
    .frame(width: 300, height: 700)

Tested with Xcode 13.2 / iOS 15.2

like image 144
Asperi Avatar answered Sep 18 '25 05:09

Asperi


This an approach for your issue, using transition with along matchedGeometryEffect in correct place:

struct ContentView: View {
    @State var details = false
    @Namespace var namespace
    private let id: String = "myID"
    var body: some View {
        
        if (details) {
            TestView1(details: $details, id: id, namespace: namespace)
        }
        else {
            TestView2(details: $details, id: id, namespace: namespace)
        }
        
    }
}


struct TestView1: View {
    @Binding var details: Bool
    let id: String
    var namespace: Namespace.ID
    var body: some View {
        
        ZStack {
          
            Color.gray.ignoresSafeArea()
            
            Color.red
                .matchedGeometryEffect(id: id, in: namespace)
                .transition(.scale(scale: 1.0))
                .frame(width: 300, height: 700)
                .onTapGesture {
                    withAnimation {
                        details = false
                    }
                }
            
        }

    }
}

struct TestView2: View {
    @Binding var details: Bool
    let id: String
    var namespace: Namespace.ID
    var body: some View {
        ZStack {
            Color.green.ignoresSafeArea()
            
            Color.red
                .matchedGeometryEffect(id: id, in: namespace)
                .transition(.scale(scale: 1.0))
                .frame(width: 200, height: 200)
                .onTapGesture {
                    withAnimation {
                        details = true
                    }
                }
        }
  
    }
}
like image 30
ios coder Avatar answered Sep 18 '25 07:09

ios coder