Enhance full image view support to work with 3 panel mode and split window views
This commit is contained in:
parent
6c562f93b5
commit
eca5f8259a
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,185 +9,178 @@
|
||||||
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
|
||||||
|
decelerationRate = UIScrollView.DecelerationRate.fast
|
||||||
|
delegate = self
|
||||||
|
}
|
||||||
|
|
||||||
private func initialize() {
|
@objc public func adjustFrameToCenter() {
|
||||||
showsVerticalScrollIndicator = false
|
|
||||||
showsHorizontalScrollIndicator = false
|
|
||||||
bouncesZoom = true
|
|
||||||
decelerationRate = UIScrollView.DecelerationRate.fast
|
|
||||||
delegate = self
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(ImageScrollView.changeOrientationNotification), name: UIDevice.orientationDidChangeNotification, object: nil)
|
guard let unwrappedZoomView = zoomView else {
|
||||||
}
|
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 {
|
||||||
|
frameToCenter.origin.x = 0
|
||||||
|
}
|
||||||
|
|
||||||
var frameToCenter = unwrappedZoomView.frame
|
// center vertically
|
||||||
|
if frameToCenter.size.height < bounds.height {
|
||||||
|
frameToCenter.origin.y = (bounds.height - frameToCenter.size.height) / 2
|
||||||
|
} else {
|
||||||
|
frameToCenter.origin.y = 0
|
||||||
|
}
|
||||||
|
|
||||||
// center horizontally
|
unwrappedZoomView.frame = frameToCenter
|
||||||
if frameToCenter.size.width < bounds.width {
|
}
|
||||||
frameToCenter.origin.x = (bounds.width - frameToCenter.size.width) / 2
|
|
||||||
} else {
|
|
||||||
frameToCenter.origin.x = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// center vertically
|
private func prepareToResize() {
|
||||||
if frameToCenter.size.height < bounds.height {
|
let boundsCenter = CGPoint(x: bounds.midX, y: bounds.midY)
|
||||||
frameToCenter.origin.y = (bounds.height - frameToCenter.size.height) / 2
|
pointToCenterAfterResize = convert(boundsCenter, to: zoomView)
|
||||||
} else {
|
|
||||||
frameToCenter.origin.y = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
private func recoverFromResizing() {
|
||||||
|
setMaxMinZoomScalesForCurrentBounds()
|
||||||
|
|
||||||
// If we're at the minimum zoom scale, preserve that by returning 0, which will be converted to the minimum
|
// restore zoom scale, first making sure it is within the allowable range.
|
||||||
// allowable scale when the scale is restored.
|
let maxZoomScale = max(minimumZoomScale, scaleToRestoreAfterResize)
|
||||||
if scaleToRestoreAfterResize <= minimumZoomScale + CGFloat(Float.ulpOfOne) {
|
zoomScale = min(maximumZoomScale, maxZoomScale)
|
||||||
scaleToRestoreAfterResize = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func recoverFromResizing() {
|
// restore center point, first making sure it is within the allowable range.
|
||||||
setMaxMinZoomScalesForCurrentBounds()
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
|
|
||||||
// restore center point, first making sure it is within the allowable range.
|
// 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)
|
||||||
|
|
||||||
// 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 realMaxOffset = min(maxOffset.x, offset.x)
|
||||||
var offset = CGPoint(x: boundsCenter.x - bounds.size.width/2.0, y: boundsCenter.y - bounds.size.height/2.0)
|
offset.x = max(minOffset.x, realMaxOffset)
|
||||||
|
|
||||||
// restore offset, adjusted to be within the allowable range
|
realMaxOffset = min(maxOffset.y, offset.y)
|
||||||
let maxOffset = maximumContentOffset()
|
offset.y = max(minOffset.y, realMaxOffset)
|
||||||
let minOffset = minimumContentOffset()
|
|
||||||
|
|
||||||
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 {
|
// MARK: - Set up
|
||||||
return CGPoint(x: contentSize.width - bounds.width,y:contentSize.height - bounds.height)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func minimumContentOffset() -> CGPoint {
|
open func setup() {
|
||||||
return CGPoint.zero
|
var topSupperView = superview
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Set up
|
while topSupperView?.superview != nil {
|
||||||
|
topSupperView = topSupperView?.superview
|
||||||
|
}
|
||||||
|
|
||||||
open func setup() {
|
// Make sure views have already layout with precise frame
|
||||||
var topSupperView = superview
|
topSupperView?.layoutIfNeeded()
|
||||||
|
}
|
||||||
|
|
||||||
while topSupperView?.superview != nil {
|
// MARK: - Display image
|
||||||
topSupperView = topSupperView?.superview
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure views have already layout with precise frame
|
@objc open func display(image: UIImage) {
|
||||||
topSupperView?.layoutIfNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Display image
|
if let zoomView = zoomView {
|
||||||
|
zoomView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
@objc open func display(image: UIImage) {
|
zoomView = UIImageView(image: image)
|
||||||
|
zoomView!.isUserInteractionEnabled = true
|
||||||
|
addSubview(zoomView!)
|
||||||
|
|
||||||
if let zoomView = zoomView {
|
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTapGestureRecognizer(_:)))
|
||||||
zoomView.removeFromSuperview()
|
tapGesture.numberOfTapsRequired = 2
|
||||||
}
|
zoomView!.addGestureRecognizer(tapGesture)
|
||||||
|
|
||||||
zoomView = UIImageView(image: image)
|
|
||||||
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
|
||||||
|
@ -197,177 +190,171 @@ open class ImageScrollView: UIScrollView {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
})
|
})
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue