mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2024-12-22 23:58:36 +01:00
Animate the transition to full screen image view
This commit is contained in:
parent
6ae36303de
commit
425b3b09a1
@ -103,6 +103,7 @@
|
||||
518651B023555EB20078E021 /* NNW3FeedsImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651A923555EB20078E021 /* NNW3FeedsImporter.swift */; };
|
||||
518651B123555EB20078E021 /* NNW3Feed.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651AA23555EB20078E021 /* NNW3Feed.swift */; };
|
||||
518651B223555EB20078E021 /* NNW3Document.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651AB23555EB20078E021 /* NNW3Document.swift */; };
|
||||
518651DA235621840078E021 /* ImageTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 518651D9235621840078E021 /* ImageTransition.swift */; };
|
||||
518B2EE82351B45600400001 /* NetNewsWire_iOSTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 840D61952029031D009BC708 /* NetNewsWire_iOSTests.swift */; };
|
||||
51934CCB230F599B006127BE /* ThemedNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CC1230F5963006127BE /* ThemedNavigationController.swift */; };
|
||||
51934CCE2310792F006127BE /* ActivityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51934CCD2310792F006127BE /* ActivityManager.swift */; };
|
||||
@ -798,6 +799,7 @@
|
||||
518651A923555EB20078E021 /* NNW3FeedsImporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3FeedsImporter.swift; sourceTree = "<group>"; };
|
||||
518651AA23555EB20078E021 /* NNW3Feed.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Feed.swift; sourceTree = "<group>"; };
|
||||
518651AB23555EB20078E021 /* NNW3Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Document.swift; sourceTree = "<group>"; };
|
||||
518651D9235621840078E021 /* ImageTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTransition.swift; sourceTree = "<group>"; };
|
||||
518B2ED22351B3DD00400001 /* NetNewsWire-iOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "NetNewsWire-iOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
518B2EE92351B4C200400001 /* NetNewsWire_iOSTests_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSTests_target.xcconfig; sourceTree = "<group>"; };
|
||||
51934CC1230F5963006127BE /* ThemedNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemedNavigationController.swift; sourceTree = "<group>"; };
|
||||
@ -1397,6 +1399,7 @@
|
||||
51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */,
|
||||
5142192923522B5500E07E2C /* ImageViewController.swift */,
|
||||
514219362352510100E07E2C /* ImageScrollView.swift */,
|
||||
518651D9235621840078E021 /* ImageTransition.swift */,
|
||||
);
|
||||
path = Article;
|
||||
sourceTree = "<group>";
|
||||
@ -2919,6 +2922,7 @@
|
||||
5183CCE9226F68D90010922C /* AccountRefreshTimer.swift in Sources */,
|
||||
51C452882265093600C03939 /* AddFeedViewController.swift in Sources */,
|
||||
51934CCE2310792F006127BE /* ActivityManager.swift in Sources */,
|
||||
518651DA235621840078E021 /* ImageTransition.swift in Sources */,
|
||||
514219372352510100E07E2C /* ImageScrollView.swift in Sources */,
|
||||
DF999FF722B5AEFA0064B687 /* SafariView.swift in Sources */,
|
||||
51C4529B22650A1000C03939 /* FaviconDownloader.swift in Sources */,
|
||||
|
@ -43,6 +43,7 @@ class ArticleViewController: UIViewController {
|
||||
}()
|
||||
|
||||
private var webView: WKWebView!
|
||||
private var transition = ImageTransition()
|
||||
|
||||
weak var coordinator: SceneCoordinator!
|
||||
|
||||
@ -65,6 +66,9 @@ class ArticleViewController: UIViewController {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var clickedImage: UIImage?
|
||||
var clickedImageFrame: CGRect?
|
||||
|
||||
var articleExtractorButtonState: ArticleExtractorButtonState {
|
||||
get {
|
||||
@ -357,17 +361,43 @@ extension ArticleViewController: WKScriptMessageHandler {
|
||||
|
||||
let base64Image = String(clickMessage.imageURL.suffix(from: range.upperBound))
|
||||
if let imageData = Data(base64Encoded: base64Image), let image = UIImage(data: imageData) {
|
||||
|
||||
let rect = CGRect(x: CGFloat(clickMessage.x), y: CGFloat(clickMessage.y), width: CGFloat(clickMessage.width), height: CGFloat(clickMessage.height))
|
||||
clickedImageFrame = webView.convert(rect, to: nil)
|
||||
clickedImage = image
|
||||
|
||||
let imageVC = UIStoryboard.main.instantiateController(ofType: ImageViewController.self)
|
||||
imageVC.image = image
|
||||
imageVC.modalPresentationStyle = .fullScreen
|
||||
imageVC.transitioningDelegate = self
|
||||
present(imageVC, animated: true)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: UIViewControllerTransitioningDelegate
|
||||
|
||||
extension ArticleViewController: UIViewControllerTransitioningDelegate {
|
||||
|
||||
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
guard let frame = clickedImageFrame, let image = clickedImage else { return nil }
|
||||
transition.originFrame = frame
|
||||
transition.originImage = image
|
||||
transition.presenting = true
|
||||
return transition
|
||||
}
|
||||
|
||||
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
transition.presenting = false
|
||||
return transition
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: JSON
|
||||
|
||||
private struct TemplateData: Codable {
|
||||
let style: String
|
||||
let body: String
|
||||
|
@ -42,6 +42,10 @@ open class ImageScrollView: UIScrollView {
|
||||
private var scaleToRestoreAfterResize: CGFloat = 1.0
|
||||
var maxScaleFromMinScale: CGFloat = 3.0
|
||||
|
||||
var zoomedFrame: CGRect {
|
||||
return convert(zoomView?.frame ?? CGRect.zero, to: nil)
|
||||
}
|
||||
|
||||
override open var frame: CGRect {
|
||||
willSet {
|
||||
if frame.equalTo(newValue) == false && newValue.equalTo(CGRect.zero) == false && imageSize.equalTo(CGSize.zero) == false {
|
||||
@ -93,16 +97,14 @@ open class ImageScrollView: UIScrollView {
|
||||
// center horizontally
|
||||
if frameToCenter.size.width < bounds.width {
|
||||
frameToCenter.origin.x = (bounds.width - frameToCenter.size.width) / 2
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
frameToCenter.origin.x = 0
|
||||
}
|
||||
|
||||
// center vertically
|
||||
if frameToCenter.size.height < bounds.height {
|
||||
frameToCenter.origin.y = (bounds.height - frameToCenter.size.height) / 2
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
frameToCenter.origin.y = 0
|
||||
}
|
||||
|
||||
@ -260,8 +262,7 @@ open class ImageScrollView: UIScrollView {
|
||||
// zoom out if it bigger than middle scale point. Else, zoom in
|
||||
if zoomScale >= maximumZoomScale / 2.0 {
|
||||
setZoomScale(minimumZoomScale, animated: true)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
let center = gestureRecognizer.location(in: gestureRecognizer.view)
|
||||
let zoomRect = zoomRectForScale(ImageScrollView.kZoomInFactorFromMinWhenDoubleTap * minimumZoomScale, center: center)
|
||||
zoom(to: zoomRect, animated: true)
|
||||
|
66
iOS/Article/ImageTransition.swift
Normal file
66
iOS/Article/ImageTransition.swift
Normal file
@ -0,0 +1,66 @@
|
||||
//
|
||||
// ImageAnimator.swift
|
||||
// NetNewsWire-iOS
|
||||
//
|
||||
// Created by Maurice Parker on 10/15/19.
|
||||
// Copyright © 2019 Ranchero Software. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class ImageTransition: NSObject, UIViewControllerAnimatedTransitioning {
|
||||
|
||||
let duration = 0.5
|
||||
var presenting = true
|
||||
var originFrame: CGRect!
|
||||
var originImage: UIImage!
|
||||
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return duration
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
|
||||
let destFrame: CGRect = {
|
||||
if presenting {
|
||||
let imageController = transitionContext.viewController(forKey: .to) as! ImageViewController
|
||||
return imageController.zoomedFrame
|
||||
} else {
|
||||
let imageController = transitionContext.viewController(forKey: .from) as! ImageViewController
|
||||
return imageController.zoomedFrame
|
||||
}
|
||||
}()
|
||||
|
||||
let initialFrame = presenting ? originFrame! : destFrame
|
||||
let targetFrame = presenting ? destFrame : originFrame!
|
||||
|
||||
let imageView = UIImageView(image: originImage)
|
||||
imageView.frame = initialFrame
|
||||
|
||||
// let xScaleFactor = presenting ? initialFrame.width / targetFrame.width : targetFrame.width / initialFrame.width
|
||||
// let yScaleFactor = presenting ? initialFrame.height / targetFrame.height : targetFrame.height / initialFrame.height
|
||||
// let scaleTransform = CGAffineTransform(scaleX: xScaleFactor, y: yScaleFactor)
|
||||
|
||||
let fromView = transitionContext.view(forKey: .from)!
|
||||
fromView.removeFromSuperview()
|
||||
|
||||
transitionContext.containerView.backgroundColor = UIColor.systemBackground
|
||||
transitionContext.containerView.addSubview(imageView)
|
||||
|
||||
UIView.animate(
|
||||
withDuration: duration,
|
||||
animations: {
|
||||
imageView.frame = targetFrame
|
||||
// imageView.transform = scaleTransform
|
||||
// imageView.center = CGPoint(x: targetFrame.midX, y: targetFrame.midY)
|
||||
}, completion: { _ in
|
||||
imageView.removeFromSuperview()
|
||||
let toView = transitionContext.view(forKey: .to)!
|
||||
transitionContext.containerView.addSubview(toView)
|
||||
transitionContext.containerView.bringSubviewToFront(toView)
|
||||
transitionContext.completeTransition(true)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -14,6 +14,9 @@ class ImageViewController: UIViewController {
|
||||
@IBOutlet weak var imageScrollView: ImageScrollView!
|
||||
|
||||
var image: UIImage!
|
||||
var zoomedFrame: CGRect {
|
||||
return imageScrollView.zoomedFrame
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
Loading…
Reference in New Issue
Block a user