Improve large image/gallery animation handling when images aren't loaded
This commit is contained in:
parent
d1913d7e69
commit
f2e08e96f3
|
@ -10,20 +10,22 @@ import UIKit
|
||||||
|
|
||||||
extension UIViewController: UIViewControllerTransitioningDelegate {
|
extension UIViewController: UIViewControllerTransitioningDelegate {
|
||||||
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||||
if presented is LargeImageViewController {
|
if let presented = presented as? LargeImageViewController,
|
||||||
|
presented.sourceInfo?.image != nil {
|
||||||
return LargeImageExpandAnimationController()
|
return LargeImageExpandAnimationController()
|
||||||
} else if let presented = presented as? GalleryViewController,
|
} else if let presented = presented as? GalleryViewController,
|
||||||
presented.sourcesInfo[presented.startIndex] != nil {
|
presented.sourcesInfo[presented.startIndex]?.image != nil {
|
||||||
return GalleryExpandAnimationController()
|
return GalleryExpandAnimationController()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||||
if let dismissed = dismissed as? LargeImageViewController {
|
if let dismissed = dismissed as? LargeImageViewController,
|
||||||
|
dismissed.imageForDismissalAnimation() != nil {
|
||||||
return LargeImageShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
return LargeImageShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
||||||
} else if let dismissed = dismissed as? GalleryViewController,
|
} else if let dismissed = dismissed as? GalleryViewController,
|
||||||
dismissed.sourcesInfo[dismissed.currentIndex] != nil {
|
dismissed.imageForDismissalAnimation() != nil {
|
||||||
return GalleryShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
return GalleryShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -97,6 +97,14 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func imageForDismissalAnimation() -> UIImage? {
|
||||||
|
if let sourceImage = sourcesInfo[currentIndex]?.image {
|
||||||
|
return sourceImage
|
||||||
|
} else {
|
||||||
|
return (pages[currentIndex] as? AttachmentViewController)?.largeImageVC?.image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Page View Controller Data Source
|
// MARK: - Page View Controller Data Source
|
||||||
|
|
||||||
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
|
||||||
|
|
|
@ -20,8 +20,12 @@ class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let containerView = transitionContext.containerView
|
||||||
|
containerView.addSubview(toVC.view)
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
||||||
guard let (image, sourceFrame, sourceCornerRadius) = toVC.sourcesInfo[toVC.startIndex] else {
|
guard let sourceInfo = toVC.sourcesInfo[toVC.startIndex],
|
||||||
|
let image = sourceInfo.image else {
|
||||||
toVC.view.frame = finalVCFrame
|
toVC.view.frame = finalVCFrame
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
|
@ -29,8 +33,6 @@ class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
|
|
||||||
let attachment = toVC.attachments[toVC.startIndex]
|
let attachment = toVC.attachments[toVC.startIndex]
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
|
||||||
|
|
||||||
let ratio = image.size.width / image.size.height
|
let ratio = image.size.width / image.size.height
|
||||||
var width = finalVCFrame.width
|
var width = finalVCFrame.width
|
||||||
var height = width / ratio
|
var height = width / ratio
|
||||||
|
@ -42,21 +44,20 @@ class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
}
|
}
|
||||||
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: sourceFrame)
|
let imageView = GIFImageView(frame: sourceInfo.frame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if attachment.url.pathExtension == "gif",
|
if attachment.url.pathExtension == "gif",
|
||||||
let data = ImageCache.attachments.get(attachment.url) {
|
let data = ImageCache.attachments.get(attachment.url) {
|
||||||
imageView.animate(withGIFData: data)
|
imageView.animate(withGIFData: data)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
imageView.layer.cornerRadius = sourceCornerRadius
|
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
||||||
imageView.layer.masksToBounds = true
|
imageView.layer.masksToBounds = true
|
||||||
|
|
||||||
let blackView = UIView(frame: finalVCFrame)
|
let blackView = UIView(frame: finalVCFrame)
|
||||||
blackView.backgroundColor = .black
|
blackView.backgroundColor = .black
|
||||||
blackView.alpha = 0
|
blackView.alpha = 0
|
||||||
|
|
||||||
containerView.addSubview(toVC.view)
|
|
||||||
containerView.addSubview(blackView)
|
containerView.addSubview(blackView)
|
||||||
containerView.addSubview(imageView)
|
containerView.addSubview(imageView)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,8 @@ class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let (image, sourceFrame, sourceCornerRadius) = fromVC.sourcesInfo[fromVC.currentIndex] else {
|
guard let sourceInfo = fromVC.sourcesInfo[fromVC.currentIndex],
|
||||||
|
let image = fromVC.imageForDismissalAnimation() else {
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -66,8 +67,8 @@ class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransi
|
||||||
|
|
||||||
let duration = transitionDuration(using: transitionContext)
|
let duration = transitionDuration(using: transitionContext)
|
||||||
UIView.animate(withDuration: duration, animations: {
|
UIView.animate(withDuration: duration, animations: {
|
||||||
imageView.frame = sourceFrame
|
imageView.frame = sourceInfo.frame
|
||||||
imageView.layer.cornerRadius = sourceCornerRadius
|
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
||||||
blackView.alpha = 0
|
blackView.alpha = 0
|
||||||
}, completion: { _ in
|
}, completion: { _ in
|
||||||
blackView.removeFromSuperview()
|
blackView.removeFromSuperview()
|
||||||
|
|
|
@ -13,7 +13,7 @@ import Gifu
|
||||||
|
|
||||||
class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
||||||
|
|
||||||
typealias SourceInfo = (image: UIImage, frame: CGRect, cornerRadius: CGFloat)
|
typealias SourceInfo = (image: UIImage?, frame: CGRect, cornerRadius: CGFloat)
|
||||||
|
|
||||||
var sourceInfo: SourceInfo?
|
var sourceInfo: SourceInfo?
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
@ -133,6 +133,10 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func imageForDismissalAnimation() -> UIImage? {
|
||||||
|
return sourceInfo?.image ?? image
|
||||||
|
}
|
||||||
|
|
||||||
func setControlsVisible(_ controlsVisible: Bool, animated: Bool) {
|
func setControlsVisible(_ controlsVisible: Bool, animated: Bool) {
|
||||||
self.controlsVisible = controlsVisible
|
self.controlsVisible = controlsVisible
|
||||||
if animated {
|
if animated {
|
||||||
|
|
|
@ -21,33 +21,35 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let containerView = transitionContext.containerView
|
||||||
|
containerView.addSubview(toVC.view)
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
||||||
guard let (image, originFrame, originCornerRadius) = toVC.sourceInfo else {
|
guard let sourceInfo = toVC.sourceInfo,
|
||||||
|
let image = sourceInfo.image else {
|
||||||
toVC.view.frame = finalVCFrame
|
toVC.view.frame = finalVCFrame
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
|
||||||
let ratio = image.size.width / image.size.height
|
let ratio = image.size.width / image.size.height
|
||||||
let width = finalVCFrame.width
|
let width = finalVCFrame.width
|
||||||
let height = width / ratio
|
let height = width / ratio
|
||||||
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: originFrame)
|
let imageView = GIFImageView(frame: sourceInfo.frame)
|
||||||
imageView.image = toVC.imageView.image!
|
imageView.image = image
|
||||||
if let gifData = toVC.gifData {
|
if let gifData = toVC.gifData {
|
||||||
imageView.animate(withGIFData: gifData)
|
imageView.animate(withGIFData: gifData)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
imageView.layer.cornerRadius = originCornerRadius
|
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
||||||
imageView.layer.masksToBounds = true
|
imageView.layer.masksToBounds = true
|
||||||
|
|
||||||
let blackView = UIView(frame: finalVCFrame)
|
let blackView = UIView(frame: finalVCFrame)
|
||||||
blackView.backgroundColor = .black
|
blackView.backgroundColor = .black
|
||||||
blackView.alpha = 0
|
blackView.alpha = 0
|
||||||
|
|
||||||
containerView.addSubview(toVC.view)
|
|
||||||
containerView.addSubview(blackView)
|
containerView.addSubview(blackView)
|
||||||
containerView.addSubview(imageView)
|
containerView.addSubview(imageView)
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,8 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let (image, finalFrame, finalCornerRadius) = fromVC.sourceInfo else {
|
guard let sourceInfo = fromVC.sourceInfo,
|
||||||
|
let image = fromVC.imageForDismissalAnimation() else {
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -59,8 +60,8 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
let duration = transitionDuration(using: transitionContext)
|
let duration = transitionDuration(using: transitionContext)
|
||||||
UIView.animate(withDuration: duration, animations: {
|
UIView.animate(withDuration: duration, animations: {
|
||||||
imageView.frame = finalFrame
|
imageView.frame = sourceInfo.frame
|
||||||
imageView.layer.cornerRadius = finalCornerRadius
|
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
||||||
blackView.alpha = 0
|
blackView.alpha = 0
|
||||||
}, completion: { _ in
|
}, completion: { _ in
|
||||||
blackView.removeFromSuperview()
|
blackView.removeFromSuperview()
|
||||||
|
|
|
@ -148,7 +148,7 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func sourceViewInfo(_ sourceView: UIImageView?) -> LargeImageViewController.SourceInfo? {
|
private func sourceViewInfo(_ sourceView: UIImageView?) -> LargeImageViewController.SourceInfo? {
|
||||||
guard let sourceView = sourceView, let image = sourceView.image else { return nil }
|
guard let sourceView = sourceView else { return nil }
|
||||||
|
|
||||||
var sourceFrame = sourceView.convert(sourceView.bounds, to: view)
|
var sourceFrame = sourceView.convert(sourceView.bounds, to: view)
|
||||||
if let scrollView = view as? UIScrollView {
|
if let scrollView = view as? UIScrollView {
|
||||||
|
@ -159,7 +159,7 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
let y = sourceFrame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY
|
let y = sourceFrame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY
|
||||||
sourceFrame = CGRect(x: x, y: y, width: width, height: height)
|
sourceFrame = CGRect(x: x, y: y, width: width, height: height)
|
||||||
}
|
}
|
||||||
return (image: image, frame: sourceFrame, cornerRadius: sourceView.layer.cornerRadius)
|
return (image: sourceView.image, frame: sourceFrame, cornerRadius: sourceView.layer.cornerRadius)
|
||||||
}
|
}
|
||||||
|
|
||||||
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
||||||
|
|
Loading…
Reference in New Issue