diff --git a/Packages/GalleryVC/Sources/GalleryVC/GalleryDismissAnimationController.swift b/Packages/GalleryVC/Sources/GalleryVC/GalleryDismissAnimationController.swift index e09d37884..11fb98663 100644 --- a/Packages/GalleryVC/Sources/GalleryVC/GalleryDismissAnimationController.swift +++ b/Packages/GalleryVC/Sources/GalleryVC/GalleryDismissAnimationController.swift @@ -47,6 +47,18 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans container.addSubview(to.view) } + // This trick does not work as well here as it does for presentation, seemingly + // because the delayFactor:0.9 still results in the snapshot fading out too quickly :/ + let sourceSnapshot = sourceView.snapshotView(afterScreenUpdates: false) + if let sourceSnapshot { + let snapshotContainer = sourceView.ancestorForInsertingSnapshot + snapshotContainer.addSubview(sourceSnapshot) + let sourceFrameInShapshotContainer = snapshotContainer.convert(sourceView.bounds, from: sourceView) + sourceSnapshot.frame = sourceFrameInShapshotContainer + sourceSnapshot.layer.opacity = 1 + self.sourceView.layer.opacity = 0 + } + let sourceFrameInContainer = container.convert(sourceView.bounds, from: sourceView) let destFrameInContainer = container.convert(itemViewController.content.view.bounds, from: itemViewController.content.view) @@ -59,6 +71,7 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans .translatedBy(x: destFrameInContainer.midX - sourceFrameInContainer.midX, y: destFrameInContainer.midY - sourceFrameInContainer.midY) .scaledBy(x: scale, y: scale) sourceView.transform = sourceToDestTransform + sourceSnapshot?.transform = sourceToDestTransform } else { appliedSourceToDestTransform = false } @@ -142,6 +155,7 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans if appliedSourceToDestTransform { self.sourceView.transform = origSourceTransform + sourceSnapshot?.transform = origSourceTransform } contentContainer.frame = sourceFrameInContainer @@ -151,7 +165,16 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans itemViewController.setControlsVisible(false, animated: false, dueToUserInteraction: false) } + if let sourceSnapshot { + animator.addAnimations({ + self.sourceView.layer.opacity = 1 + sourceSnapshot.layer.opacity = 0 + }, delayFactor: 0.9) + } + animator.addCompletion { _ in + sourceSnapshot?.removeFromSuperview() + // Having dismissed, we don't need to undo any of the changes to the content VC. transitionContext.completeTransition(true) diff --git a/Packages/GalleryVC/Sources/GalleryVC/GalleryPresentationAnimationController.swift b/Packages/GalleryVC/Sources/GalleryVC/GalleryPresentationAnimationController.swift index 94d7eb786..3f33b3bc6 100644 --- a/Packages/GalleryVC/Sources/GalleryVC/GalleryPresentationAnimationController.swift +++ b/Packages/GalleryVC/Sources/GalleryVC/GalleryPresentationAnimationController.swift @@ -30,6 +30,25 @@ class GalleryPresentationAnimationController: NSObject, UIViewControllerAnimated return } + // Try to effectively "fade out" anything that's on top of the source view. + // The 0.05 duration makes this happen faster than the rest of the animation, + // and so less noticeable. + let sourceSnapshot = sourceView.snapshotView(afterScreenUpdates: false) + if let sourceSnapshot { + let snapshotContainer = sourceView.ancestorForInsertingSnapshot + snapshotContainer.addSubview(sourceSnapshot) + let sourceFrameInShapshotContainer = snapshotContainer.convert(sourceView.bounds, from: sourceView) + sourceSnapshot.frame = sourceFrameInShapshotContainer + sourceSnapshot.transform = sourceView.transform + sourceSnapshot.layer.opacity = 0 + UIView.animate(withDuration: 0.05) { + sourceSnapshot.layer.opacity = 1 + // Also fade out the actual source view underneath the snapshot to try + // and account for semi-transparent images. + self.sourceView.layer.opacity = 0 + } + } + let container = transitionContext.containerView to.view.frame = container.bounds container.addSubview(to.view) @@ -149,20 +168,23 @@ class GalleryPresentationAnimationController: NSObject, UIViewControllerAnimated itemViewController.setControlsVisible(true, animated: false, dueToUserInteraction: false) if let sourceToDestTransform { + sourceSnapshot?.transform = sourceToDestTransform self.sourceView.transform = sourceToDestTransform } } animator.addCompletion { _ in + sourceSnapshot?.removeFromSuperview() + self.sourceView.layer.opacity = 1 + if sourceToDestTransform != nil { + self.sourceView.transform = origSourceTransform + } + contentContainer.removeFromSuperview() dimmingView.removeFromSuperview() to.view.backgroundColor = .black - if sourceToDestTransform != nil { - self.sourceView.transform = origSourceTransform - } - // Reset the properties we changed before re-adding the content to the scroll view. // (I would expect UIScrollView to effectively do this itself, but w/e.) content.view.transform = origContentTransform diff --git a/Packages/GalleryVC/Sources/GalleryVC/UIView+Utilities.swift b/Packages/GalleryVC/Sources/GalleryVC/UIView+Utilities.swift new file mode 100644 index 000000000..411122bee --- /dev/null +++ b/Packages/GalleryVC/Sources/GalleryVC/UIView+Utilities.swift @@ -0,0 +1,26 @@ +// +// UIView+Utilities.swift +// GalleryVC +// +// Created by Shadowfacts on 11/24/24. +// + +import UIKit + +extension UIView { + + var ancestorForInsertingSnapshot: UIView { + var view = self + while let superview = view.superview { + if superview.layer.masksToBounds { + return superview + } else if superview is UIScrollView { + return self + } else { + view = superview + } + } + return view + } + +}