{"componentChunkName":"component---src-templates-article-js","path":"/article/matchedgeometryeffect-overview","result":{"data":{"contentfulArticle":{"title":"MatchedGeometryEffect Overview","image":"https://res.cloudinary.com/liquidcoder/image/upload/v1616687966/Blog/matchedGeometryEffect/psicuyfldctkjiw1sjbl.jpg","createdDate":"Thursday, 25 March 2021","videoUrl":null,"updatedDate":"2 years ago","isNewLayout":true,"previews":{"previews":"{\n\t\"MatchedGeometryEffect2\": [\"https://res.cloudinary.com/liquidcoder/image/upload/v1615971432/Blog/matchedGeometryEffect/xk9u7ors7kckkoa8okx8.gif\"],\n\t\"MatchedGeometryEffect4\": [\"https://res.cloudinary.com/liquidcoder/image/upload/v1615971430/Blog/matchedGeometryEffect/ijbpbizxxokajbd25clv.gif\"],\n\t\"MatchedGeometryEffect6\": [\"https://res.cloudinary.com/liquidcoder/image/upload/v1616006181/Blog/matchedGeometryEffect/i9or0da3z052sze4zoca.gif\"]\n}"},"slug":"matchedgeometryeffect-overview","author":{"email":"john@liquidcoder.com","name":"John"},"tags":[{"title":"Swift UI"},{"title":"iOS App Development"},{"title":"Mobile App Development"}],"allChapters":null,"code":{"childMdx":{"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"\\n// $$liquidcoderID-MatchedGeometryEffectIntro\\n\\nfunc matchedGeometryEffect<ID>(id: ID, in namespace: Namespace.ID, properties: MatchedGeometryProperties = .frame, anchor: UnitPoint = .center, isSource: Bool = true) -> some View where ID : Hashable\\n\")), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"// $$liquidcoderID-MatchedGeometryEffect2\\n// $$liquidcoderFilename-ContentView\\n\\nimport SwiftUI\\n\\nstruct ContentView: View {\\n\\n    // highlight-start\\n    @State private var animate = false\\n    // highlight-end\\n\\n    var body: some View {\\n\\n        VStack {\\n            if animate {\\n    // highlight-start\\n                VStack {\\n                    Image(\\\"image\\\")\\n                        .resizable()\\n                        .scaledToFill()\\n                        .frame(height: 300, alignment: .center)\\n                }.frame(maxHeight: .infinity, alignment: .top)\\n                .edgesIgnoringSafeArea(.all)\\n                .onTapGesture {\\n                    self.animate.toggle()\\n                }\\n    // highlight-end\\n            }\\n\\n            if !animate {\\n    // highlight-start\\n                Image(\\\"image\\\")\\n                    .resizable()\\n                    .scaledToFill()\\n                    .frame(width: 250, height: 300, alignment: .center)\\n                    .onTapGesture {\\n                        self.animate.toggle()\\n                    }\\n    // highlight-end\\n            }\\n        }.animation(.easeIn)\\n    }\\n}\\n\\nstruct ContentView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        ContentView()\\n    }\\n}\\n\")), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"// $$liquidcoderID-MatchedGeometryEffect4\\n// $$liquidcoderFilename-ContentView\\n\\nimport SwiftUI\\n\\nstruct ContentView: View {\\n\\n    // highlight-start\\n    @Namespace var animation\\n    // highlight-end\\n    @State private var animate = false\\n\\n    var body: some View {\\n\\n        VStack {\\n            if animate {\\n                VStack {\\n                    Image(\\\"image\\\")\\n                        .resizable()\\n                        .scaledToFill()\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"ID\\\", in: animation)\\n                        // highlight-end\\n                        .frame(height: 300, alignment: .center)\\n                }.frame(maxHeight: .infinity, alignment: .top)\\n                .edgesIgnoringSafeArea(.all)\\n                .onTapGesture {\\n                    self.animate.toggle()\\n                }\\n            }\\n\\n            if !animate {\\n                Image(\\\"image\\\")\\n                    .resizable()\\n                    .scaledToFill()\\n                    // highlight-start\\n                    .matchedGeometryEffect(id: \\\"ID\\\", in: animation)\\n                    // highlight-end\\n                    .frame(width: 250, height: 300, alignment: .center)\\n                    .onTapGesture {\\n                        self.animate.toggle()\\n                    }\\n            }\\n        }.animation(.easeIn)\\n    }\\n}\\n\\nstruct ContentView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        ContentView()\\n    }\\n}\\n\")), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"// $$liquidcoderID-MatchedGeometryEffect6\\n// $$liquidcoderFilename-ContentView\\n\\nimport SwiftUI\\n\\nstruct ContentView: View {\\n\\n    @Namespace var animation\\n    @State private var animate = false\\n\\n    var body: some View {\\n\\n        VStack {\\n            if animate {\\n                HStack {\\n\\n                    Rectangle()\\n                        .foregroundColor(.green)\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"backward.end.alt.fill\\\", in: animation)\\n                        // highlight-end\\n                        .frame(width: 50, height: 50, alignment: .center)\\n\\n                    Rectangle()\\n                        .foregroundColor(.red)\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"stop.fill\\\", in: animation)\\n                        // highlight-end\\n                        .frame(width: 50, height: 50, alignment: .center)\\n\\n                    Rectangle()\\n                        .foregroundColor(.blue)\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"forward.end.alt.fill\\\", in: animation)\\n                        // highlight-end\\n                        .frame(width: 50, height: 50, alignment: .center)\\n\\n                }.frame(height: 300, alignment: .top)\\n                .edgesIgnoringSafeArea(.all)\\n                .onTapGesture {\\n                    self.animate.toggle()\\n                }\\n            }\\n\\n            if !animate {\\n                Rectangle()\\n                    // highlight-start\\n                    .matchedGeometryEffect(id: \\\"backward.end.alt.fill\\\", in: animation)\\n                    .matchedGeometryEffect(id: \\\"stop.fill\\\", in: animation)\\n                    .matchedGeometryEffect(id: \\\"forward.end.alt.fill\\\", in: animation)\\n                    // highlight-end\\n                    .frame(width: 30, height: 30, alignment: .center)\\n                    .onTapGesture {\\n                        self.animate.toggle()\\n                    }\\n            }\\n        }.animation(.easeIn)\\n    }\\n}\\n\")));\n}\n;\nMDXContent.isMDXComponent = true;"}},"explanation":{"childMdx":{"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"div\", {\n    id: \"MatchedGeometryEffectIntro-Section\",\n    className: \"post-section\"\n  }, mdx(\"h2\", null, \"Introduction\"), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"Apple says: \\\"Defines a group of views with synchronized geometry using an identifier and namespace that you provide.\\\"\"))), mdx(\"div\", {\n    id: \"MatchedGeometryEffect1-Section\",\n    className: \"post-section\"\n  }, mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"Also this method sets the geometry of each view in the group from the inserted view with isSource = true (known as the \\u201Csource\\u201D view), updating the values marked by properties.\")), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"If inserting a view in the same transaction that another view with the same key is removed, the system will interpolate their frame rectangles in window space to make it appear that there is a single view moving from its old position to its new position. The usual transition mechanisms define how each of the two views is rendered during the transition (e.g. fade in/out, scale, etc), the matchedGeometryEffect() modifier only arranges for the geometry of the views to be linked, not their rendering.\"))), mdx(\"div\", {\n    id: \"MatchedGeometryEffect2-Section\",\n    className: \"post-section\"\n  }, mdx(\"p\", null, \"Take a look at this code. The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"animate\"), \" boolean state will be toggled when either the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"VStack\"), \" or the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image\"), \" is tapped, and when this happens, we want to hide one and show the other.\"), mdx(\"p\", null, \"We don't have any transition for now.\")), mdx(\"div\", {\n    id: \"MatchedGeometryEffect3-Section\",\n    className: \"post-section\"\n  }, mdx(\"p\", null, \"Now let's add the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifier into the mix.\")), mdx(\"div\", {\n    id: \"MatchedGeometryEffect4-Section\",\n    className: \"post-section\"\n  }, mdx(\"p\", null, \"We first need declare this \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"animation\"), \" with this \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"@Namespace\"), \" property wrapper that we then pass in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifier to both \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image\"), \" views.\")), mdx(\"div\", {\n    id: \"MatchedGeometryEffect5-Section\",\n    className: \"post-section\"\n  }, mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"NOTE:\"), \" The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"id\"), \" must be the same for both views involved in the transition, and the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifier must be added before the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"frame\"), \".\"))), mdx(\"div\", {\n    id: \"MatchedGeometryEffect6-Section\",\n    className: \"post-section\"\n  }, mdx(\"h2\", null, \"Multiple MGR Modifiers\"), mdx(\"p\", null, \"It is also possible to add multiple \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifiers on a single views pointing to multiple views.\")), mdx(\"div\", {\n    id: \"MatchedGeometryEffect7-Section\",\n    className: \"post-section\"\n  }, mdx(\"h2\", null, \"No more than one visible view\"), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"If the number of currently-inserted views in the group with isSource = true is not exactly one results are undefined, due to it not being clear which is the source view.\")), mdx(\"p\", null, \"For the effect to work, only one view from the 2 views with the same id   must be visible at any given time.\")), mdx(\"div\", {\n    id: \"MatchedGeometryEffectOutro-Section\",\n    className: \"post-section\"\n  }, mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryEffect\"), \" modifier is magical, it's mind-blowing what swiftUI  has accomplished with just one function call.\")));\n}\n;\nMDXContent.isMDXComponent = true;"}},"downloads":null,"resources":[{"name":"Apple developer documentation","url":"https://developer.apple.com/documentation/homekit/cameraview/3594025-matchedgeometryeffect"}],"body":{"childMdx":{"tableOfContents":{"items":[{"url":"#introduction","title":"Introduction"},{"url":"#multiple-mgr-modifiers","title":"Multiple MGR Modifiers"},{"url":"#no-more-than-one-visible-view","title":"No more than one visible view"}]},"body":"function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nvar _frontmatter = {};\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n      props = _objectWithoutProperties(_ref, [\"components\"]);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"h2\", null, \"Introduction\"), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"Apple says: \\\"Defines a group of views with synchronized geometry using an identifier and namespace that you provide.\\\"\")), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"// $$liquidcoderID-MatchedGeometryEffectIntro\\n\\nfunc matchedGeometryEffect<ID>(id: ID, in namespace: Namespace.ID, properties: MatchedGeometryProperties = .frame, anchor: UnitPoint = .center, isSource: Bool = true) -> some View where ID : Hashable\\n\")), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"Also this method sets the geometry of each view in the group from the inserted view with isSource = true (known as the \\u201Csource\\u201D view), updating the values marked by properties.\")), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"If inserting a view in the same transaction that another view with the same key is removed, the system will interpolate their frame rectangles in window space to make it appear that there is a single view moving from its old position to its new position. The usual transition mechanisms define how each of the two views is rendered during the transition (e.g. fade in/out, scale, etc), the matchedGeometryEffect() modifier only arranges for the geometry of the views to be linked, not their rendering.\")), mdx(\"p\", null, \"Take a look at this code. The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"animate\"), \" boolean state will be toggled when either the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"VStack\"), \" or the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image\"), \" is tapped, and when this happens, we want to hide one and show the other.\"), mdx(\"p\", null, \"We don't have any transition for now.\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"// $$liquidcoderID-MatchedGeometryEffect2\\n// $$liquidcoderFilename-ContentView\\n\\nimport SwiftUI\\n\\nstruct ContentView: View {\\n\\n    // highlight-start\\n    @State private var animate = false\\n    // highlight-end\\n\\n    var body: some View {\\n\\n        VStack {\\n            if animate {\\n    // highlight-start\\n                VStack {\\n                    Image(\\\"image\\\")\\n                        .resizable()\\n                        .scaledToFill()\\n                        .frame(height: 300, alignment: .center)\\n                }.frame(maxHeight: .infinity, alignment: .top)\\n                .edgesIgnoringSafeArea(.all)\\n                .onTapGesture {\\n                    self.animate.toggle()\\n                }\\n    // highlight-end\\n            }\\n\\n            if !animate {\\n    // highlight-start\\n                Image(\\\"image\\\")\\n                    .resizable()\\n                    .scaledToFill()\\n                    .frame(width: 250, height: 300, alignment: .center)\\n                    .onTapGesture {\\n                        self.animate.toggle()\\n                    }\\n    // highlight-end\\n            }\\n        }.animation(.easeIn)\\n    }\\n}\\n\\nstruct ContentView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        ContentView()\\n    }\\n}\\n\")), mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1615971432/Blog/matchedGeometryEffect/xk9u7ors7kckkoa8okx8.gif\",\n    \"alt\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1615971432/Blog/matchedGeometryEffect/xk9u7ors7kckkoa8okx8.gif\"\n  }))), mdx(\"p\", null, \"Now let's add the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifier into the mix.\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"// $$liquidcoderID-MatchedGeometryEffect4\\n// $$liquidcoderFilename-ContentView\\n\\nimport SwiftUI\\n\\nstruct ContentView: View {\\n\\n    // highlight-start\\n    @Namespace var animation\\n    // highlight-end\\n    @State private var animate = false\\n\\n    var body: some View {\\n\\n        VStack {\\n            if animate {\\n                VStack {\\n                    Image(\\\"image\\\")\\n                        .resizable()\\n                        .scaledToFill()\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"ID\\\", in: animation)\\n                        // highlight-end\\n                        .frame(height: 300, alignment: .center)\\n                }.frame(maxHeight: .infinity, alignment: .top)\\n                .edgesIgnoringSafeArea(.all)\\n                .onTapGesture {\\n                    self.animate.toggle()\\n                }\\n            }\\n\\n            if !animate {\\n                Image(\\\"image\\\")\\n                    .resizable()\\n                    .scaledToFill()\\n                    // highlight-start\\n                    .matchedGeometryEffect(id: \\\"ID\\\", in: animation)\\n                    // highlight-end\\n                    .frame(width: 250, height: 300, alignment: .center)\\n                    .onTapGesture {\\n                        self.animate.toggle()\\n                    }\\n            }\\n        }.animation(.easeIn)\\n    }\\n}\\n\\nstruct ContentView_Previews: PreviewProvider {\\n    static var previews: some View {\\n        ContentView()\\n    }\\n}\\n\")), mdx(\"p\", null, \"We first need declare this \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"animation\"), \" with this \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"@Namespace\"), \" property wrapper that we then pass in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifier to both \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"Image\"), \" views.\"), mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1615971430/Blog/matchedGeometryEffect/ijbpbizxxokajbd25clv.gif\",\n    \"alt\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1615971430/Blog/matchedGeometryEffect/ijbpbizxxokajbd25clv.gif\"\n  }))), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, mdx(\"strong\", {\n    parentName: \"p\"\n  }, \"NOTE:\"), \" The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"id\"), \" must be the same for both views involved in the transition, and the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifier must be added before the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"frame\"), \".\")), mdx(\"h2\", null, \"Multiple MGR Modifiers\"), mdx(\"p\", null, \"It is also possible to add multiple \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryReader\"), \" modifiers on a single views pointing to multiple views.\"), mdx(\"pre\", null, mdx(\"code\", _extends({\n    parentName: \"pre\"\n  }, {\n    \"className\": \"language-swift\"\n  }), \"// $$liquidcoderID-MatchedGeometryEffect6\\n// $$liquidcoderFilename-ContentView\\n\\nimport SwiftUI\\n\\nstruct ContentView: View {\\n\\n    @Namespace var animation\\n    @State private var animate = false\\n\\n    var body: some View {\\n\\n        VStack {\\n            if animate {\\n                HStack {\\n\\n                    Rectangle()\\n                        .foregroundColor(.green)\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"backward.end.alt.fill\\\", in: animation)\\n                        // highlight-end\\n                        .frame(width: 50, height: 50, alignment: .center)\\n\\n                    Rectangle()\\n                        .foregroundColor(.red)\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"stop.fill\\\", in: animation)\\n                        // highlight-end\\n                        .frame(width: 50, height: 50, alignment: .center)\\n\\n                    Rectangle()\\n                        .foregroundColor(.blue)\\n                        // highlight-start\\n                        .matchedGeometryEffect(id: \\\"forward.end.alt.fill\\\", in: animation)\\n                        // highlight-end\\n                        .frame(width: 50, height: 50, alignment: .center)\\n\\n                }.frame(height: 300, alignment: .top)\\n                .edgesIgnoringSafeArea(.all)\\n                .onTapGesture {\\n                    self.animate.toggle()\\n                }\\n            }\\n\\n            if !animate {\\n                Rectangle()\\n                    // highlight-start\\n                    .matchedGeometryEffect(id: \\\"backward.end.alt.fill\\\", in: animation)\\n                    .matchedGeometryEffect(id: \\\"stop.fill\\\", in: animation)\\n                    .matchedGeometryEffect(id: \\\"forward.end.alt.fill\\\", in: animation)\\n                    // highlight-end\\n                    .frame(width: 30, height: 30, alignment: .center)\\n                    .onTapGesture {\\n                        self.animate.toggle()\\n                    }\\n            }\\n        }.animation(.easeIn)\\n    }\\n}\\n\")), mdx(\"p\", null, mdx(\"img\", _extends({\n    parentName: \"p\"\n  }, {\n    \"src\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1616006181/Blog/matchedGeometryEffect/i9or0da3z052sze4zoca.gif\",\n    \"alt\": \"https://res.cloudinary.com/liquidcoder/image/upload/v1616006181/Blog/matchedGeometryEffect/i9or0da3z052sze4zoca.gif\"\n  }))), mdx(\"h2\", null, \"No more than one visible view\"), mdx(\"blockquote\", null, mdx(\"p\", {\n    parentName: \"blockquote\"\n  }, \"If the number of currently-inserted views in the group with isSource = true is not exactly one results are undefined, due to it not being clear which is the source view.\")), mdx(\"p\", null, \"For the effect to work, only one view from the 2 views with the same id   must be visible at any given time.\"), mdx(\"p\", null, \"The \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"matchedGeometryEffect\"), \" modifier is magical, it's mind-blowing what swiftUI  has accomplished with just one function call.\"));\n}\n;\nMDXContent.isMDXComponent = true;","excerpt":"Introduction Apple says: \"Defines a group of views with synchronized geometry using an identifier and namespace that you provide.\" Also this method sets the geometry of each view in the group from the inserted view with isSource = true (known as the “source” view), updating the values marked by…"}}}},"pageContext":{"slug":"matchedgeometryeffect-overview"}},"staticQueryHashes":["1047155515","1278771865","2517639938","2517639938","2537039069","3452127246","3566879862","3891201089","439617394","670651827"]}