forked from shadowfacts/Tusker
Merge gallery and large image animations
This commit is contained in:
parent
955f9e5916
commit
2e8c416e04
|
@ -13,8 +13,6 @@
|
||||||
0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */; };
|
0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */; };
|
||||||
0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */; };
|
0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */; };
|
||||||
0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450531E22B0097E00100BA2 /* Timline+UI.swift */; };
|
0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450531E22B0097E00100BA2 /* Timline+UI.swift */; };
|
||||||
0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */; };
|
|
||||||
0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */; };
|
|
||||||
04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4022B2FFB10021BD04 /* PreferencesView.swift */; };
|
04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4022B2FFB10021BD04 /* PreferencesView.swift */; };
|
||||||
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4222B301470021BD04 /* AppearancePrefsView.swift */; };
|
04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4222B301470021BD04 /* AppearancePrefsView.swift */; };
|
||||||
0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; };
|
0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; };
|
||||||
|
@ -297,8 +295,6 @@
|
||||||
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsView.swift; sourceTree = "<group>"; };
|
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsView.swift; sourceTree = "<group>"; };
|
||||||
0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SilentActionPrefs.swift; sourceTree = "<group>"; };
|
0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SilentActionPrefs.swift; sourceTree = "<group>"; };
|
||||||
0450531E22B0097E00100BA2 /* Timline+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timline+UI.swift"; sourceTree = "<group>"; };
|
0450531E22B0097E00100BA2 /* Timline+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timline+UI.swift"; sourceTree = "<group>"; };
|
||||||
0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryExpandAnimationController.swift; sourceTree = "<group>"; };
|
|
||||||
0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryShrinkAnimationController.swift; sourceTree = "<group>"; };
|
|
||||||
04586B4022B2FFB10021BD04 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
04586B4022B2FFB10021BD04 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = "<group>"; };
|
||||||
04586B4222B301470021BD04 /* AppearancePrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePrefsView.swift; sourceTree = "<group>"; };
|
04586B4222B301470021BD04 /* AppearancePrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePrefsView.swift; sourceTree = "<group>"; };
|
||||||
0461A38F2163CBAE00C0A807 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
0461A38F2163CBAE00C0A807 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
@ -584,21 +580,11 @@
|
||||||
0411610522B457290030A9B7 /* Gallery */ = {
|
0411610522B457290030A9B7 /* Gallery */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
0411610622B457360030A9B7 /* Transitions */,
|
|
||||||
04D14BAE22B34A2800642648 /* GalleryViewController.swift */,
|
04D14BAE22B34A2800642648 /* GalleryViewController.swift */,
|
||||||
);
|
);
|
||||||
path = Gallery;
|
path = Gallery;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
0411610622B457360030A9B7 /* Transitions */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */,
|
|
||||||
0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */,
|
|
||||||
);
|
|
||||||
path = Transitions;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
D61099AC2144B0CC00432DC2 /* Pachyderm */ = {
|
D61099AC2144B0CC00432DC2 /* Pachyderm */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1630,7 +1616,6 @@
|
||||||
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */,
|
D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */,
|
||||||
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
|
D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */,
|
||||||
D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */,
|
D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */,
|
||||||
0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */,
|
|
||||||
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */,
|
D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */,
|
||||||
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */,
|
D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */,
|
||||||
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
|
D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */,
|
||||||
|
@ -1664,7 +1649,6 @@
|
||||||
D64BC18823C1640A000D0238 /* PinStatusActivity.swift in Sources */,
|
D64BC18823C1640A000D0238 /* PinStatusActivity.swift in Sources */,
|
||||||
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */,
|
D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */,
|
||||||
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */,
|
||||||
0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */,
|
|
||||||
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */,
|
||||||
D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */,
|
D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */,
|
||||||
D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */,
|
D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */,
|
||||||
|
|
|
@ -10,23 +10,17 @@ 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 let presented = presented as? LargeImageViewController,
|
if let presented = presented as? LargeImageAnimatableViewController,
|
||||||
presented.sourceInfo?.image != nil {
|
presented.animationImage != nil {
|
||||||
return LargeImageExpandAnimationController()
|
return LargeImageExpandAnimationController()
|
||||||
} else if let presented = presented as? GalleryViewController,
|
|
||||||
presented.sourcesInfo[presented.startIndex]?.image != nil {
|
|
||||||
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? LargeImageAnimatableViewController,
|
||||||
dismissed.imageForDismissalAnimation() != nil {
|
dismissed.animationImage != nil {
|
||||||
return LargeImageShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
return LargeImageShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
||||||
} else if let dismissed = dismissed as? GalleryViewController,
|
|
||||||
dismissed.imageForDismissalAnimation() != nil {
|
|
||||||
return GalleryShrinkAnimationController(interactionController: dismissed.dismissInteractionController)
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -36,10 +30,6 @@ extension UIViewController: UIViewControllerTransitioningDelegate {
|
||||||
let interactionController = animator.interactionController,
|
let interactionController = animator.interactionController,
|
||||||
interactionController.inProgress {
|
interactionController.inProgress {
|
||||||
return interactionController
|
return interactionController
|
||||||
} else if let animator = animator as? GalleryShrinkAnimationController,
|
|
||||||
let interactionController = animator.interactionController,
|
|
||||||
interactionController.inProgress {
|
|
||||||
return interactionController
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,7 @@ import Pachyderm
|
||||||
import AVFoundation
|
import AVFoundation
|
||||||
import AVKit
|
import AVKit
|
||||||
|
|
||||||
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
|
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, LargeImageAnimatableViewController {
|
||||||
|
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
|
||||||
|
|
||||||
let attachments: [Attachment]
|
let attachments: [Attachment]
|
||||||
let sourcesInfo: [LargeImageViewController.SourceInfo?]
|
let sourcesInfo: [LargeImageViewController.SourceInfo?]
|
||||||
|
@ -28,6 +26,24 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var animationSourceInfo: LargeImageViewController.SourceInfo? { sourcesInfo[currentIndex] }
|
||||||
|
var animationImage: UIImage? {
|
||||||
|
if let sourceImage = sourcesInfo[currentIndex]?.image {
|
||||||
|
return sourceImage
|
||||||
|
} else {
|
||||||
|
return (pages[currentIndex] as? AttachmentViewController)?.largeImageVC?.image
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var animationGifData: Data? {
|
||||||
|
let attachment = attachments[currentIndex]
|
||||||
|
if attachment.url.pathExtension == "gif" {
|
||||||
|
return ImageCache.attachments.get(attachment.url)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
||||||
override var prefersStatusBarHidden: Bool {
|
override var prefersStatusBarHidden: Bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -97,14 +113,6 @@ 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? {
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
// GalleryExpandAnimationController.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 6/14/19.
|
|
||||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Gifu
|
|
||||||
|
|
||||||
class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
|
||||||
return 0.2
|
|
||||||
}
|
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from),
|
|
||||||
let toVC = transitionContext.viewController(forKey: .to) as? GalleryViewController else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
|
||||||
containerView.addSubview(toVC.view)
|
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
|
||||||
guard let sourceInfo = toVC.sourcesInfo[toVC.startIndex],
|
|
||||||
let image = sourceInfo.image else {
|
|
||||||
toVC.view.frame = finalVCFrame
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let attachment = toVC.attachments[toVC.startIndex]
|
|
||||||
|
|
||||||
let ratio = image.size.width / image.size.height
|
|
||||||
var width = finalVCFrame.width
|
|
||||||
var height = width / ratio
|
|
||||||
let maxHeight = fromVC.view.bounds.height - fromVC.view.safeAreaInsets.top - fromVC.view.safeAreaInsets.bottom
|
|
||||||
if height > maxHeight {
|
|
||||||
let scaleFactor = maxHeight / height
|
|
||||||
width *= scaleFactor
|
|
||||||
height = maxHeight
|
|
||||||
}
|
|
||||||
let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height)
|
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: sourceInfo.frame)
|
|
||||||
imageView.image = image
|
|
||||||
if attachment.url.pathExtension == "gif",
|
|
||||||
let data = ImageCache.attachments.get(attachment.url) {
|
|
||||||
imageView.animate(withGIFData: data)
|
|
||||||
}
|
|
||||||
imageView.contentMode = .scaleAspectFill
|
|
||||||
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
|
||||||
imageView.layer.masksToBounds = true
|
|
||||||
|
|
||||||
let blackView = UIView(frame: finalVCFrame)
|
|
||||||
blackView.backgroundColor = .black
|
|
||||||
blackView.alpha = 0
|
|
||||||
|
|
||||||
containerView.addSubview(blackView)
|
|
||||||
containerView.addSubview(imageView)
|
|
||||||
|
|
||||||
toVC.view.isHidden = true
|
|
||||||
|
|
||||||
let duration = transitionDuration(using: transitionContext)
|
|
||||||
UIView.animate(withDuration: duration, animations: {
|
|
||||||
imageView.frame = finalFrame
|
|
||||||
imageView.layer.cornerRadius = 0
|
|
||||||
blackView.alpha = 1
|
|
||||||
}, completion: { _ in
|
|
||||||
toVC.view.frame = finalVCFrame
|
|
||||||
|
|
||||||
toVC.view.isHidden = false
|
|
||||||
fromVC.view.isHidden = false
|
|
||||||
blackView.removeFromSuperview()
|
|
||||||
imageView.removeFromSuperview()
|
|
||||||
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,84 +0,0 @@
|
||||||
// GalleryShrinkAnimationController.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 6/14/19.
|
|
||||||
// Copyright © 2019 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Gifu
|
|
||||||
|
|
||||||
class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
|
||||||
|
|
||||||
let interactionController: LargeImageInteractionController?
|
|
||||||
|
|
||||||
init(interactionController: LargeImageInteractionController?) {
|
|
||||||
self.interactionController = interactionController
|
|
||||||
}
|
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
|
||||||
return 0.2
|
|
||||||
}
|
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from) as? GalleryViewController,
|
|
||||||
let toVC = transitionContext.viewController(forKey: .to) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let sourceInfo = fromVC.sourcesInfo[fromVC.currentIndex],
|
|
||||||
let image = fromVC.imageForDismissalAnimation() else {
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let originalVCFrame = fromVC.view.frame
|
|
||||||
|
|
||||||
let attachment = fromVC.attachments[fromVC.currentIndex]
|
|
||||||
|
|
||||||
let ratio = image.size.width / image.size.height
|
|
||||||
var width = originalVCFrame.width
|
|
||||||
var height = width / ratio
|
|
||||||
let maxHeight = fromVC.view.bounds.height - fromVC.view.safeAreaInsets.top - fromVC.view.safeAreaInsets.bottom
|
|
||||||
if height > maxHeight {
|
|
||||||
let scaleFactor = maxHeight / height
|
|
||||||
width *= scaleFactor
|
|
||||||
height = maxHeight
|
|
||||||
}
|
|
||||||
let originalFrame = CGRect(x: originalVCFrame.midX - width / 2, y: originalVCFrame.midY - height / 2, width: width, height: height)
|
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: originalFrame)
|
|
||||||
imageView.image = image
|
|
||||||
if attachment.url.pathExtension == "gif",
|
|
||||||
let data = ImageCache.attachments.get(attachment.url) {
|
|
||||||
imageView.animate(withGIFData: data)
|
|
||||||
}
|
|
||||||
imageView.contentMode = .scaleAspectFill
|
|
||||||
imageView.layer.cornerRadius = 0
|
|
||||||
imageView.layer.masksToBounds = true
|
|
||||||
|
|
||||||
let blackView = UIView(frame: originalVCFrame)
|
|
||||||
blackView.backgroundColor = .black
|
|
||||||
blackView.alpha = 1
|
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
|
||||||
containerView.addSubview(toVC.view)
|
|
||||||
containerView.addSubview(blackView)
|
|
||||||
containerView.addSubview(imageView)
|
|
||||||
|
|
||||||
let duration = transitionDuration(using: transitionContext)
|
|
||||||
UIView.animate(withDuration: duration, animations: {
|
|
||||||
imageView.frame = sourceInfo.frame
|
|
||||||
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
|
||||||
blackView.alpha = 0
|
|
||||||
}, completion: { _ in
|
|
||||||
blackView.removeFromSuperview()
|
|
||||||
imageView.removeFromSuperview()
|
|
||||||
|
|
||||||
if transitionContext.transitionWasCancelled {
|
|
||||||
toVC.view.removeFromSuperview()
|
|
||||||
}
|
|
||||||
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -11,11 +11,13 @@ import Pachyderm
|
||||||
import Photos
|
import Photos
|
||||||
import Gifu
|
import Gifu
|
||||||
|
|
||||||
class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeImageAnimatableViewController {
|
||||||
|
|
||||||
typealias SourceInfo = (image: UIImage?, frame: CGRect, cornerRadius: CGFloat)
|
typealias SourceInfo = (image: UIImage?, frame: CGRect, cornerRadius: CGFloat)
|
||||||
|
|
||||||
var sourceInfo: SourceInfo?
|
var animationSourceInfo: SourceInfo?
|
||||||
|
var animationImage: UIImage? { animationSourceInfo?.image ?? image }
|
||||||
|
var animationGifData: Data? { gifData }
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
||||||
@IBOutlet weak var scrollView: UIScrollView!
|
@IBOutlet weak var scrollView: UIScrollView!
|
||||||
|
@ -62,7 +64,7 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate {
|
||||||
init(image: UIImage, description: String?, sourceInfo: SourceInfo?) {
|
init(image: UIImage, description: String?, sourceInfo: SourceInfo?) {
|
||||||
self.image = image
|
self.image = image
|
||||||
self.imageDescription = description
|
self.imageDescription = description
|
||||||
self.sourceInfo = sourceInfo
|
self.animationSourceInfo = sourceInfo
|
||||||
|
|
||||||
super.init(nibName: "LargeImageViewController", bundle: nil)
|
super.init(nibName: "LargeImageViewController", bundle: nil)
|
||||||
|
|
||||||
|
@ -128,10 +130,6 @@ 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 {
|
||||||
|
|
|
@ -9,6 +9,13 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import Gifu
|
import Gifu
|
||||||
|
|
||||||
|
protocol LargeImageAnimatableViewController: UIViewController {
|
||||||
|
var animationSourceInfo: LargeImageViewController.SourceInfo? { get }
|
||||||
|
var animationImage: UIImage? { get }
|
||||||
|
var animationGifData: Data? { get }
|
||||||
|
var dismissInteractionController: LargeImageInteractionController? { get }
|
||||||
|
}
|
||||||
|
|
||||||
class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||||
|
@ -17,7 +24,7 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from),
|
guard let fromVC = transitionContext.viewController(forKey: .from),
|
||||||
let toVC = transitionContext.viewController(forKey: .to) as? LargeImageViewController else {
|
let toVC = transitionContext.viewController(forKey: .to) as? LargeImageAnimatableViewController else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,8 +32,8 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
containerView.addSubview(toVC.view)
|
containerView.addSubview(toVC.view)
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
||||||
guard let sourceInfo = toVC.sourceInfo,
|
guard let sourceInfo = toVC.animationSourceInfo,
|
||||||
let image = sourceInfo.image else {
|
let image = toVC.animationImage else {
|
||||||
toVC.view.frame = finalVCFrame
|
toVC.view.frame = finalVCFrame
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
|
@ -39,7 +46,7 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: sourceInfo.frame)
|
let imageView = GIFImageView(frame: sourceInfo.frame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if let gifData = toVC.gifData {
|
if let gifData = toVC.animationGifData {
|
||||||
imageView.animate(withGIFData: gifData)
|
imageView.animate(withGIFData: gifData)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
|
|
@ -22,13 +22,13 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
}
|
}
|
||||||
|
|
||||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||||
guard let fromVC = transitionContext.viewController(forKey: .from) as? LargeImageViewController,
|
guard let fromVC = transitionContext.viewController(forKey: .from) as? LargeImageAnimatableViewController,
|
||||||
let toVC = transitionContext.viewController(forKey: .to) else {
|
let toVC = transitionContext.viewController(forKey: .to) else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let sourceInfo = fromVC.sourceInfo,
|
guard let sourceInfo = fromVC.animationSourceInfo,
|
||||||
let image = fromVC.imageForDismissalAnimation() else {
|
let image = fromVC.animationImage else {
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: originalFrame)
|
let imageView = GIFImageView(frame: originalFrame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if let gifData = fromVC.gifData {
|
if let gifData = fromVC.animationGifData {
|
||||||
imageView.animate(withGIFData: gifData)
|
imageView.animate(withGIFData: gifData)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
|
|
Loading…
Reference in New Issue