Enhance full image view support to work with 3 panel mode and split window views

This commit is contained in:
Maurice Parker 2019-10-16 20:20:36 -05:00
parent 6c562f93b5
commit eca5f8259a
5 changed files with 337 additions and 341 deletions

View File

@ -444,11 +444,7 @@ private extension ArticleViewController {
transition.maskFrame = webView.convert(webView.frame, to: nil) transition.maskFrame = webView.convert(webView.frame, to: nil)
transition.originImage = image transition.originImage = image
let imageVC = UIStoryboard.main.instantiateController(ofType: ImageViewController.self) coordinator.showFullScreenImage(image: image, transitioningDelegate: self)
imageVC.image = image
imageVC.modalPresentationStyle = .fullScreen
imageVC.transitioningDelegate = self
present(imageVC, animated: true)
} }
} }

View File

@ -9,365 +9,352 @@
import UIKit import UIKit
@objc public protocol ImageScrollViewDelegate: UIScrollViewDelegate { @objc public protocol ImageScrollViewDelegate: UIScrollViewDelegate {
func imageScrollViewDidChangeOrientation(imageScrollView: ImageScrollView)
func imageScrollViewDidGestureSwipeUp(imageScrollView: ImageScrollView) func imageScrollViewDidGestureSwipeUp(imageScrollView: ImageScrollView)
func imageScrollViewDidGestureSwipeDown(imageScrollView: ImageScrollView) func imageScrollViewDidGestureSwipeDown(imageScrollView: ImageScrollView)
} }
open class ImageScrollView: UIScrollView { open class ImageScrollView: UIScrollView {
@objc public enum ScaleMode: Int { @objc public enum ScaleMode: Int {
case aspectFill case aspectFill
case aspectFit case aspectFit
case widthFill case widthFill
case heightFill case heightFill
} }
@objc public enum Offset: Int { @objc public enum Offset: Int {
case begining case begining
case center case center
} }
static let kZoomInFactorFromMinWhenDoubleTap: CGFloat = 2 static let kZoomInFactorFromMinWhenDoubleTap: CGFloat = 2
@objc open var imageContentMode: ScaleMode = .widthFill @objc open var imageContentMode: ScaleMode = .widthFill
@objc open var initialOffset: Offset = .begining @objc open var initialOffset: Offset = .begining
@objc public private(set) var zoomView: UIImageView? = nil @objc public private(set) var zoomView: UIImageView? = nil
@objc open weak var imageScrollViewDelegate: ImageScrollViewDelegate? @objc open weak var imageScrollViewDelegate: ImageScrollViewDelegate?
var imageSize: CGSize = CGSize.zero var imageSize: CGSize = CGSize.zero
private var pointToCenterAfterResize: CGPoint = CGPoint.zero private var pointToCenterAfterResize: CGPoint = CGPoint.zero
private var scaleToRestoreAfterResize: CGFloat = 1.0 private var scaleToRestoreAfterResize: CGFloat = 1.0
var maxScaleFromMinScale: CGFloat = 3.0 var maxScaleFromMinScale: CGFloat = 3.0
var zoomedFrame: CGRect { var zoomedFrame: CGRect {
return zoomView?.frame ?? CGRect.zero return zoomView?.frame ?? CGRect.zero
} }
override open var frame: CGRect { override open var frame: CGRect {
willSet { willSet {
if frame.equalTo(newValue) == false && newValue.equalTo(CGRect.zero) == false && imageSize.equalTo(CGSize.zero) == false { if frame.equalTo(newValue) == false && newValue.equalTo(CGRect.zero) == false && imageSize.equalTo(CGSize.zero) == false {
prepareToResize() prepareToResize()
} }
} }
didSet { didSet {
if frame.equalTo(oldValue) == false && frame.equalTo(CGRect.zero) == false && imageSize.equalTo(CGSize.zero) == false { if frame.equalTo(oldValue) == false && frame.equalTo(CGRect.zero) == false && imageSize.equalTo(CGSize.zero) == false {
recoverFromResizing() recoverFromResizing()
} }
} }
} }
override public init(frame: CGRect) { override public init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
initialize() initialize()
} }
required public init?(coder aDecoder: NSCoder) { required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) super.init(coder: aDecoder)
initialize() initialize()
} }
deinit { private func initialize() {
NotificationCenter.default.removeObserver(self) showsVerticalScrollIndicator = false
} showsHorizontalScrollIndicator = false
bouncesZoom = true
private func initialize() { decelerationRate = UIScrollView.DecelerationRate.fast
showsVerticalScrollIndicator = false delegate = self
showsHorizontalScrollIndicator = false }
bouncesZoom = true
decelerationRate = UIScrollView.DecelerationRate.fast @objc public func adjustFrameToCenter() {
delegate = self
guard let unwrappedZoomView = zoomView else {
NotificationCenter.default.addObserver(self, selector: #selector(ImageScrollView.changeOrientationNotification), name: UIDevice.orientationDidChangeNotification, object: nil) return
} }
@objc public func adjustFrameToCenter() { var frameToCenter = unwrappedZoomView.frame
guard let unwrappedZoomView = zoomView else { // center horizontally
return if frameToCenter.size.width < bounds.width {
} frameToCenter.origin.x = (bounds.width - frameToCenter.size.width) / 2
} else {
var frameToCenter = unwrappedZoomView.frame frameToCenter.origin.x = 0
}
// center horizontally
if frameToCenter.size.width < bounds.width { // center vertically
frameToCenter.origin.x = (bounds.width - frameToCenter.size.width) / 2 if frameToCenter.size.height < bounds.height {
} else { frameToCenter.origin.y = (bounds.height - frameToCenter.size.height) / 2
frameToCenter.origin.x = 0 } else {
} frameToCenter.origin.y = 0
}
// center vertically
if frameToCenter.size.height < bounds.height { unwrappedZoomView.frame = frameToCenter
frameToCenter.origin.y = (bounds.height - frameToCenter.size.height) / 2 }
} else {
frameToCenter.origin.y = 0 private func prepareToResize() {
} let boundsCenter = CGPoint(x: bounds.midX, y: bounds.midY)
pointToCenterAfterResize = convert(boundsCenter, to: zoomView)
unwrappedZoomView.frame = frameToCenter
} scaleToRestoreAfterResize = zoomScale
private func prepareToResize() { // If we're at the minimum zoom scale, preserve that by returning 0, which will be converted to the minimum
let boundsCenter = CGPoint(x: bounds.midX, y: bounds.midY) // allowable scale when the scale is restored.
pointToCenterAfterResize = convert(boundsCenter, to: zoomView) if scaleToRestoreAfterResize <= minimumZoomScale + CGFloat(Float.ulpOfOne) {
scaleToRestoreAfterResize = 0
scaleToRestoreAfterResize = zoomScale }
}
// If we're at the minimum zoom scale, preserve that by returning 0, which will be converted to the minimum
// allowable scale when the scale is restored. private func recoverFromResizing() {
if scaleToRestoreAfterResize <= minimumZoomScale + CGFloat(Float.ulpOfOne) { setMaxMinZoomScalesForCurrentBounds()
scaleToRestoreAfterResize = 0
} // restore zoom scale, first making sure it is within the allowable range.
} let maxZoomScale = max(minimumZoomScale, scaleToRestoreAfterResize)
zoomScale = min(maximumZoomScale, maxZoomScale)
private func recoverFromResizing() {
setMaxMinZoomScalesForCurrentBounds() // restore center point, first making sure it is within the allowable range.
// restore zoom scale, first making sure it is within the allowable range. // convert our desired center point back to our own coordinate space
let maxZoomScale = max(minimumZoomScale, scaleToRestoreAfterResize) let boundsCenter = convert(pointToCenterAfterResize, to: zoomView)
zoomScale = min(maximumZoomScale, maxZoomScale)
// calculate the content offset that would yield that center point
// restore center point, first making sure it is within the allowable range. var offset = CGPoint(x: boundsCenter.x - bounds.size.width/2.0, y: boundsCenter.y - bounds.size.height/2.0)
// convert our desired center point back to our own coordinate space // restore offset, adjusted to be within the allowable range
let boundsCenter = convert(pointToCenterAfterResize, to: zoomView) let maxOffset = maximumContentOffset()
let minOffset = minimumContentOffset()
// calculate the content offset that would yield that center point
var offset = CGPoint(x: boundsCenter.x - bounds.size.width/2.0, y: boundsCenter.y - bounds.size.height/2.0) var realMaxOffset = min(maxOffset.x, offset.x)
offset.x = max(minOffset.x, realMaxOffset)
// restore offset, adjusted to be within the allowable range
let maxOffset = maximumContentOffset() realMaxOffset = min(maxOffset.y, offset.y)
let minOffset = minimumContentOffset() offset.y = max(minOffset.y, realMaxOffset)
var realMaxOffset = min(maxOffset.x, offset.x) contentOffset = offset
offset.x = max(minOffset.x, realMaxOffset) }
realMaxOffset = min(maxOffset.y, offset.y) private func maximumContentOffset() -> CGPoint {
offset.y = max(minOffset.y, realMaxOffset) return CGPoint(x: contentSize.width - bounds.width,y:contentSize.height - bounds.height)
}
contentOffset = offset
} private func minimumContentOffset() -> CGPoint {
return CGPoint.zero
private func maximumContentOffset() -> CGPoint { }
return CGPoint(x: contentSize.width - bounds.width,y:contentSize.height - bounds.height)
} // MARK: - Set up
private func minimumContentOffset() -> CGPoint { open func setup() {
return CGPoint.zero var topSupperView = superview
}
while topSupperView?.superview != nil {
// MARK: - Set up topSupperView = topSupperView?.superview
}
open func setup() {
var topSupperView = superview // Make sure views have already layout with precise frame
topSupperView?.layoutIfNeeded()
while topSupperView?.superview != nil { }
topSupperView = topSupperView?.superview
} // MARK: - Display image
// Make sure views have already layout with precise frame @objc open func display(image: UIImage) {
topSupperView?.layoutIfNeeded()
} if let zoomView = zoomView {
zoomView.removeFromSuperview()
// MARK: - Display image }
@objc open func display(image: UIImage) { zoomView = UIImageView(image: image)
zoomView!.isUserInteractionEnabled = true
if let zoomView = zoomView { addSubview(zoomView!)
zoomView.removeFromSuperview()
} let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTapGestureRecognizer(_:)))
tapGesture.numberOfTapsRequired = 2
zoomView = UIImageView(image: image) zoomView!.addGestureRecognizer(tapGesture)
zoomView!.isUserInteractionEnabled = true
addSubview(zoomView!)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTapGestureRecognizer(_:)))
tapGesture.numberOfTapsRequired = 2
zoomView!.addGestureRecognizer(tapGesture)
let downSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeUpGestureRecognizer(_:))) let downSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeUpGestureRecognizer(_:)))
downSwipeGesture.direction = .down downSwipeGesture.direction = .down
zoomView!.addGestureRecognizer(downSwipeGesture) zoomView!.addGestureRecognizer(downSwipeGesture)
let upSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeDownGestureRecognizer(_:))) let upSwipeGesture = UISwipeGestureRecognizer(target: self, action: #selector(swipeDownGestureRecognizer(_:)))
upSwipeGesture.direction = .up upSwipeGesture.direction = .up
zoomView!.addGestureRecognizer(upSwipeGesture) zoomView!.addGestureRecognizer(upSwipeGesture)
configureImageForSize(image.size) configureImageForSize(image.size)
} }
private func configureImageForSize(_ size: CGSize) { private func configureImageForSize(_ size: CGSize) {
imageSize = size imageSize = size
contentSize = imageSize contentSize = imageSize
setMaxMinZoomScalesForCurrentBounds() setMaxMinZoomScalesForCurrentBounds()
zoomScale = minimumZoomScale zoomScale = minimumZoomScale
switch initialOffset { switch initialOffset {
case .begining: case .begining:
contentOffset = CGPoint.zero contentOffset = CGPoint.zero
case .center: case .center:
let xOffset = contentSize.width < bounds.width ? 0 : (contentSize.width - bounds.width)/2 let xOffset = contentSize.width < bounds.width ? 0 : (contentSize.width - bounds.width)/2
let yOffset = contentSize.height < bounds.height ? 0 : (contentSize.height - bounds.height)/2 let yOffset = contentSize.height < bounds.height ? 0 : (contentSize.height - bounds.height)/2
switch imageContentMode { switch imageContentMode {
case .aspectFit: case .aspectFit:
contentOffset = CGPoint.zero contentOffset = CGPoint.zero
case .aspectFill: case .aspectFill:
contentOffset = CGPoint(x: xOffset, y: yOffset) contentOffset = CGPoint(x: xOffset, y: yOffset)
case .heightFill: case .heightFill:
contentOffset = CGPoint(x: xOffset, y: 0) contentOffset = CGPoint(x: xOffset, y: 0)
case .widthFill: case .widthFill:
contentOffset = CGPoint(x: 0, y: yOffset) contentOffset = CGPoint(x: 0, y: yOffset)
} }
} }
} }
private func setMaxMinZoomScalesForCurrentBounds() { private func setMaxMinZoomScalesForCurrentBounds() {
// calculate min/max zoomscale // calculate min/max zoomscale
let xScale = bounds.width / imageSize.width // the scale needed to perfectly fit the image width-wise let xScale = bounds.width / imageSize.width // the scale needed to perfectly fit the image width-wise
let yScale = bounds.height / imageSize.height // the scale needed to perfectly fit the image height-wise let yScale = bounds.height / imageSize.height // the scale needed to perfectly fit the image height-wise
var minScale: CGFloat = 1 var minScale: CGFloat = 1
switch imageContentMode { switch imageContentMode {
case .aspectFill: case .aspectFill:
minScale = max(xScale, yScale) minScale = max(xScale, yScale)
case .aspectFit: case .aspectFit:
minScale = min(xScale, yScale) minScale = min(xScale, yScale)
case .widthFill: case .widthFill:
minScale = xScale minScale = xScale
case .heightFill: case .heightFill:
minScale = yScale minScale = yScale
} }
let maxScale = maxScaleFromMinScale*minScale let maxScale = maxScaleFromMinScale*minScale
// don't let minScale exceed maxScale. (If the image is smaller than the screen, we don't want to force it to be zoomed.) // don't let minScale exceed maxScale. (If the image is smaller than the screen, we don't want to force it to be zoomed.)
if minScale > maxScale { if minScale > maxScale {
minScale = maxScale minScale = maxScale
} }
maximumZoomScale = maxScale maximumZoomScale = maxScale
minimumZoomScale = minScale * 0.999 // the multiply factor to prevent user cannot scroll page while they use this control in UIPageViewController minimumZoomScale = minScale * 0.999 // the multiply factor to prevent user cannot scroll page while they use this control in UIPageViewController
} }
// MARK: - Gesture // MARK: - Gesture
@objc func doubleTapGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) { @objc func doubleTapGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) {
// zoom out if it bigger than middle scale point. Else, zoom in // zoom out if it bigger than middle scale point. Else, zoom in
if zoomScale >= maximumZoomScale / 2.0 { if zoomScale >= maximumZoomScale / 2.0 {
setZoomScale(minimumZoomScale, animated: true) setZoomScale(minimumZoomScale, animated: true)
} else { } else {
let center = gestureRecognizer.location(in: gestureRecognizer.view) let center = gestureRecognizer.location(in: gestureRecognizer.view)
let zoomRect = zoomRectForScale(ImageScrollView.kZoomInFactorFromMinWhenDoubleTap * minimumZoomScale, center: center) let zoomRect = zoomRectForScale(ImageScrollView.kZoomInFactorFromMinWhenDoubleTap * minimumZoomScale, center: center)
zoom(to: zoomRect, animated: true) zoom(to: zoomRect, animated: true)
} }
} }
@objc func swipeUpGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) { @objc func swipeUpGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer.state == .ended { if gestureRecognizer.state == .ended {
imageScrollViewDelegate?.imageScrollViewDidGestureSwipeUp(imageScrollView: self) imageScrollViewDelegate?.imageScrollViewDidGestureSwipeUp(imageScrollView: self)
} }
} }
@objc func swipeDownGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) { @objc func swipeDownGestureRecognizer(_ gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer.state == .ended { if gestureRecognizer.state == .ended {
imageScrollViewDelegate?.imageScrollViewDidGestureSwipeDown(imageScrollView: self) imageScrollViewDelegate?.imageScrollViewDidGestureSwipeDown(imageScrollView: self)
} }
} }
private func zoomRectForScale(_ scale: CGFloat, center: CGPoint) -> CGRect { private func zoomRectForScale(_ scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero var zoomRect = CGRect.zero
// the zoom rect is in the content view's coordinates. // the zoom rect is in the content view's coordinates.
// at a zoom scale of 1.0, it would be the size of the imageScrollView's bounds. // at a zoom scale of 1.0, it would be the size of the imageScrollView's bounds.
// as the zoom scale decreases, so more content is visible, the size of the rect grows. // as the zoom scale decreases, so more content is visible, the size of the rect grows.
zoomRect.size.height = frame.size.height / scale zoomRect.size.height = frame.size.height / scale
zoomRect.size.width = frame.size.width / scale zoomRect.size.width = frame.size.width / scale
// choose an origin so as to get the right center. // choose an origin so as to get the right center.
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0) zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0)
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0) zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0)
return zoomRect return zoomRect
} }
open func refresh() { open func refresh() {
if let image = zoomView?.image { if let image = zoomView?.image {
display(image: image) display(image: image)
} }
} }
// MARK: - Actions open func resize() {
self.configureImageForSize(self.imageSize)
@objc func changeOrientationNotification() { }
// A weird bug that frames are not update right after orientation changed. Need delay a little bit with async.
DispatchQueue.main.async {
self.configureImageForSize(self.imageSize)
self.imageScrollViewDelegate?.imageScrollViewDidChangeOrientation(imageScrollView: self)
}
}
} }
extension ImageScrollView: UIScrollViewDelegate { extension ImageScrollView: UIScrollViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) { public func scrollViewDidScroll(_ scrollView: UIScrollView) {
imageScrollViewDelegate?.scrollViewDidScroll?(scrollView) imageScrollViewDelegate?.scrollViewDidScroll?(scrollView)
} }
public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { public func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
imageScrollViewDelegate?.scrollViewWillBeginDragging?(scrollView) imageScrollViewDelegate?.scrollViewWillBeginDragging?(scrollView)
} }
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
imageScrollViewDelegate?.scrollViewWillEndDragging?(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset) imageScrollViewDelegate?.scrollViewWillEndDragging?(scrollView, withVelocity: velocity, targetContentOffset: targetContentOffset)
} }
public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
imageScrollViewDelegate?.scrollViewDidEndDragging?(scrollView, willDecelerate: decelerate) imageScrollViewDelegate?.scrollViewDidEndDragging?(scrollView, willDecelerate: decelerate)
} }
public func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) { public func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
imageScrollViewDelegate?.scrollViewWillBeginDecelerating?(scrollView) imageScrollViewDelegate?.scrollViewWillBeginDecelerating?(scrollView)
} }
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
imageScrollViewDelegate?.scrollViewDidEndDecelerating?(scrollView) imageScrollViewDelegate?.scrollViewDidEndDecelerating?(scrollView)
} }
public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
imageScrollViewDelegate?.scrollViewDidEndScrollingAnimation?(scrollView) imageScrollViewDelegate?.scrollViewDidEndScrollingAnimation?(scrollView)
} }
public func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) { public func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
imageScrollViewDelegate?.scrollViewWillBeginZooming?(scrollView, with: view) imageScrollViewDelegate?.scrollViewWillBeginZooming?(scrollView, with: view)
} }
public func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) { public func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {
imageScrollViewDelegate?.scrollViewDidEndZooming?(scrollView, with: view, atScale: scale) imageScrollViewDelegate?.scrollViewDidEndZooming?(scrollView, with: view, atScale: scale)
} }
public func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool { public func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
return false return false
} }
@available(iOS 11.0, *) @available(iOS 11.0, *)
public func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView) { public func scrollViewDidChangeAdjustedContentInset(_ scrollView: UIScrollView) {
imageScrollViewDelegate?.scrollViewDidChangeAdjustedContentInset?(scrollView) imageScrollViewDelegate?.scrollViewDidChangeAdjustedContentInset?(scrollView)
} }
public func viewForZooming(in scrollView: UIScrollView) -> UIView? { public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return zoomView return zoomView
} }
public func scrollViewDidZoom(_ scrollView: UIScrollView) { public func scrollViewDidZoom(_ scrollView: UIScrollView) {
adjustFrameToCenter() adjustFrameToCenter()
imageScrollViewDelegate?.scrollViewDidZoom?(scrollView) imageScrollViewDelegate?.scrollViewDidZoom?(scrollView)
} }
} }

View File

@ -28,6 +28,13 @@ class ImageViewController: UIViewController {
imageScrollView.display(image: image) imageScrollView.display(image: image)
} }
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { [weak self] context in
self?.imageScrollView.resize()
})
}
@IBAction func share(_ sender: Any) { @IBAction func share(_ sender: Any) {
guard let image = image else { return } guard let image = image else { return }
let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil) let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil)
@ -46,9 +53,6 @@ class ImageViewController: UIViewController {
extension ImageViewController: ImageScrollViewDelegate { extension ImageViewController: ImageScrollViewDelegate {
func imageScrollViewDidChangeOrientation(imageScrollView: ImageScrollView) {
}
func imageScrollViewDidGestureSwipeUp(imageScrollView: ImageScrollView) { func imageScrollViewDidGestureSwipeUp(imageScrollView: ImageScrollView) {
dismiss(animated: true) dismiss(animated: true)
} }

View File

@ -14,6 +14,7 @@ class RootSplitViewController: UISplitViewController {
var coordinator: SceneCoordinator! var coordinator: SceneCoordinator!
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { [weak self] context in coordinator.animate(alongsideTransition: { [weak self] context in
self?.coordinator.configureThreePanelMode(for: size) self?.coordinator.configureThreePanelMode(for: size)
}) })

View File

@ -819,6 +819,14 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
masterFeedViewController.present(addViewController, animated: true) masterFeedViewController.present(addViewController, animated: true)
} }
func showFullScreenImage(image: UIImage, transitioningDelegate: UIViewControllerTransitioningDelegate) {
let imageVC = UIStoryboard.main.instantiateController(ofType: ImageViewController.self)
imageVC.image = image
imageVC.modalPresentationStyle = .currentContext
imageVC.transitioningDelegate = transitioningDelegate
rootSplitViewController.present(imageVC, animated: true)
}
func toggleArticleExtractor() { func toggleArticleExtractor() {
guard let article = currentArticle else { guard let article = currentArticle else {