Improve gallery transitions when there is something displaying on top of the source view
See #520
This commit is contained in:
parent
f44dae632c
commit
a99fb7f0b0
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue