From 23f447bfa87b26c6aace5b6f90696df88d3c91a4 Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Tue, 16 Jan 2024 15:58:18 -0500 Subject: [PATCH] Hero Transition corrections --- site/posts/2023-05-21-swiftui-hero-transition.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/site/posts/2023-05-21-swiftui-hero-transition.md b/site/posts/2023-05-21-swiftui-hero-transition.md index a7505e8..c1e7268 100644 --- a/site/posts/2023-05-21-swiftui-hero-transition.md +++ b/site/posts/2023-05-21-swiftui-hero-transition.md @@ -122,6 +122,8 @@ func updateUIViewController(_ uiViewController: UIViewController, context: Conte } ``` +Lastly, we can declare an extension on `View` called `presentViewController` which takes the same arguments as the modifier type and applies it to `self`. + ## The Approach Now that we have the ability to present a custom view controller, let's think about what that VC actually needs to contain for the matched geometry effect. The transition we want to achieve is split into two parts: the matched geometry and everything else. The frames of the views being matched should animate smoothly from source to destination, and the views themselves should be visible the entire time. The rest of the presented content, however, is not matched and should appear with some other animation. There are multiple options, but I'm going to go with a simple fade-in. @@ -235,7 +237,7 @@ struct MatchedGeometrySourceModifier: ViewModifier { func body(content: Content) -> some View { content - .background(GeometryReader { + .background(GeometryReader { proxy in Color.clear .preference(key: MatchedGeometrySourcesKey.self, value: [ id: (AnyView(matched), proxy.frame(in: .global)) @@ -309,7 +311,7 @@ override func viewDidLoad() { super.viewDidLoad() let sources = self.sources.map { (id: $0.key, view: $0.value.0, frame: $0.value.1) } - let matchedContainer = MatchedContainerView(sources: sources) + let matchedContainer = MatchedContainerView(sources: sources, state: state) matchedHost = UIHostingController(rootView: matchedContainer) matchedHost.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] matchedHost.view.frame = view.bounds @@ -331,6 +333,7 @@ The container view for the matched views will, for now, just display all of the ```swift struct MatchedContainerView: View { let sources: [(id: AnyHashable, view: AnyView, frame: CGRect)] + @ObservedObject var state: MatchedGeometryState var body: some View { ZStack { @@ -623,7 +626,7 @@ The other piece of the puzzle is that `UIViewPropertyAnimator` will call the com func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { // ... - matchedGeomVC.view.layer.opacity = 0 + matchedGeomVC.contentHost.view.layer.opacity = 0 let spring = UISpringTimingParameters(mass: 1, stiffness: 150, damping: 15, initialVelocity: .zero) let animator = UIViewPropertyAnimator(duration: self.transitionDuration(using: transitionContext), timingParameters: spring) animator.addAnimations {