skip to Main Content

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
                    }
                }
        }
    }
}

2

Answers


  1. 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
                        }
                    }
            }
      
        }
    }
    
    Login or Signup to reply.
  2. 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

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search