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)
|
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 sourceFrameInContainer = container.convert(sourceView.bounds, from: sourceView)
|
||||||
let destFrameInContainer = container.convert(itemViewController.content.view.bounds, from: itemViewController.content.view)
|
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)
|
.translatedBy(x: destFrameInContainer.midX - sourceFrameInContainer.midX, y: destFrameInContainer.midY - sourceFrameInContainer.midY)
|
||||||
.scaledBy(x: scale, y: scale)
|
.scaledBy(x: scale, y: scale)
|
||||||
sourceView.transform = sourceToDestTransform
|
sourceView.transform = sourceToDestTransform
|
||||||
|
sourceSnapshot?.transform = sourceToDestTransform
|
||||||
} else {
|
} else {
|
||||||
appliedSourceToDestTransform = false
|
appliedSourceToDestTransform = false
|
||||||
}
|
}
|
||||||
|
@ -142,6 +155,7 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans
|
||||||
|
|
||||||
if appliedSourceToDestTransform {
|
if appliedSourceToDestTransform {
|
||||||
self.sourceView.transform = origSourceTransform
|
self.sourceView.transform = origSourceTransform
|
||||||
|
sourceSnapshot?.transform = origSourceTransform
|
||||||
}
|
}
|
||||||
|
|
||||||
contentContainer.frame = sourceFrameInContainer
|
contentContainer.frame = sourceFrameInContainer
|
||||||
|
@ -151,7 +165,16 @@ class GalleryDismissAnimationController: NSObject, UIViewControllerAnimatedTrans
|
||||||
itemViewController.setControlsVisible(false, animated: false, dueToUserInteraction: false)
|
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
|
animator.addCompletion { _ in
|
||||||
|
sourceSnapshot?.removeFromSuperview()
|
||||||
|
|
||||||
// Having dismissed, we don't need to undo any of the changes to the content VC.
|
// Having dismissed, we don't need to undo any of the changes to the content VC.
|
||||||
|
|
||||||
transitionContext.completeTransition(true)
|
transitionContext.completeTransition(true)
|
||||||
|
|
|
@ -30,6 +30,25 @@ class GalleryPresentationAnimationController: NSObject, UIViewControllerAnimated
|
||||||
return
|
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
|
let container = transitionContext.containerView
|
||||||
to.view.frame = container.bounds
|
to.view.frame = container.bounds
|
||||||
container.addSubview(to.view)
|
container.addSubview(to.view)
|
||||||
|
@ -149,20 +168,23 @@ class GalleryPresentationAnimationController: NSObject, UIViewControllerAnimated
|
||||||
itemViewController.setControlsVisible(true, animated: false, dueToUserInteraction: false)
|
itemViewController.setControlsVisible(true, animated: false, dueToUserInteraction: false)
|
||||||
|
|
||||||
if let sourceToDestTransform {
|
if let sourceToDestTransform {
|
||||||
|
sourceSnapshot?.transform = sourceToDestTransform
|
||||||
self.sourceView.transform = sourceToDestTransform
|
self.sourceView.transform = sourceToDestTransform
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
animator.addCompletion { _ in
|
animator.addCompletion { _ in
|
||||||
|
sourceSnapshot?.removeFromSuperview()
|
||||||
|
self.sourceView.layer.opacity = 1
|
||||||
|
if sourceToDestTransform != nil {
|
||||||
|
self.sourceView.transform = origSourceTransform
|
||||||
|
}
|
||||||
|
|
||||||
contentContainer.removeFromSuperview()
|
contentContainer.removeFromSuperview()
|
||||||
dimmingView.removeFromSuperview()
|
dimmingView.removeFromSuperview()
|
||||||
|
|
||||||
to.view.backgroundColor = .black
|
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.
|
// 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.)
|
// (I would expect UIScrollView to effectively do this itself, but w/e.)
|
||||||
content.view.transform = origContentTransform
|
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