Files
Lightbox/Source/Views/PageView.swift
T
Kristaps Grinbergs 6af9321ea9 * Swift 4.2 and Xcode 10
* SwiftLint warnings and errors, added some short variable names in config
* Example project to Swift 4.2 and Xcode 10
* bump version
2018-09-23 13:25:03 +03:00

232 lines
6.0 KiB
Swift

import UIKit
protocol PageViewDelegate: class {
func pageViewDidZoom(_ pageView: PageView)
func remoteImageDidLoad(_ image: UIImage?, imageView: UIImageView)
func pageView(_ pageView: PageView, didTouchPlayButton videoURL: URL)
func pageViewDidTouch(_ pageView: PageView)
}
class PageView: UIScrollView {
lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.isUserInteractionEnabled = true
return imageView
}()
lazy var playButton: UIButton = {
let button = UIButton(type: .custom)
button.frame.size = CGSize(width: 60, height: 60)
button.setBackgroundImage(AssetManager.image("lightbox_play"), for: UIControl.State())
button.addTarget(self, action: #selector(playButtonTouched(_:)), for: .touchUpInside)
button.layer.shadowOffset = CGSize(width: 1, height: 1)
button.layer.shadowColor = UIColor.gray.cgColor
button.layer.masksToBounds = false
button.layer.shadowOpacity = 0.8
return button
}()
lazy var loadingIndicator: UIView = LightboxConfig.makeLoadingIndicator()
var image: LightboxImage
var contentFrame = CGRect.zero
weak var pageViewDelegate: PageViewDelegate?
var hasZoomed: Bool {
return zoomScale != 1.0
}
// MARK: - Initializers
init(image: LightboxImage) {
self.image = image
super.init(frame: CGRect.zero)
configure()
fetchImage()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Configuration
func configure() {
addSubview(imageView)
updatePlayButton()
addSubview(loadingIndicator)
delegate = self
isMultipleTouchEnabled = true
minimumZoomScale = LightboxConfig.Zoom.minimumScale
maximumZoomScale = LightboxConfig.Zoom.maximumScale
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(scrollViewDoubleTapped(_:)))
doubleTapRecognizer.numberOfTapsRequired = 2
doubleTapRecognizer.numberOfTouchesRequired = 1
addGestureRecognizer(doubleTapRecognizer)
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:)))
addGestureRecognizer(tapRecognizer)
tapRecognizer.require(toFail: doubleTapRecognizer)
}
// MARK: - Update
func update(with image: LightboxImage) {
self.image = image
updatePlayButton()
fetchImage()
}
func updatePlayButton () {
if self.image.videoURL != nil && !subviews.contains(playButton) {
addSubview(playButton)
} else if self.image.videoURL == nil && subviews.contains(playButton) {
playButton.removeFromSuperview()
}
}
// MARK: - Fetch
private func fetchImage () {
loadingIndicator.alpha = 1
self.image.addImageTo(imageView) { [weak self] image in
guard let self = self else {
return
}
self.isUserInteractionEnabled = true
self.configureImageView()
self.pageViewDelegate?.remoteImageDidLoad(image, imageView: self.imageView)
UIView.animate(withDuration: 0.4) {
self.loadingIndicator.alpha = 0
}
}
}
// MARK: - Recognizers
@objc func scrollViewDoubleTapped(_ recognizer: UITapGestureRecognizer) {
let pointInView = recognizer.location(in: imageView)
let newZoomScale = zoomScale > minimumZoomScale
? minimumZoomScale
: maximumZoomScale
let width = contentFrame.size.width / newZoomScale
let height = contentFrame.size.height / newZoomScale
let x = pointInView.x - (width / 2.0)
let y = pointInView.y - (height / 2.0)
let rectToZoomTo = CGRect(x: x, y: y, width: width, height: height)
zoom(to: rectToZoomTo, animated: true)
}
@objc func viewTapped(_ recognizer: UITapGestureRecognizer) {
pageViewDelegate?.pageViewDidTouch(self)
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
loadingIndicator.center = imageView.center
playButton.center = imageView.center
}
func configureImageView() {
guard let image = imageView.image else {
centerImageView()
return
}
let imageViewSize = imageView.frame.size
let imageSize = image.size
let realImageViewSize: CGSize
if imageSize.width / imageSize.height > imageViewSize.width / imageViewSize.height {
realImageViewSize = CGSize(
width: imageViewSize.width,
height: imageViewSize.width / imageSize.width * imageSize.height)
} else {
realImageViewSize = CGSize(
width: imageViewSize.height / imageSize.height * imageSize.width,
height: imageViewSize.height)
}
imageView.frame = CGRect(origin: CGPoint.zero, size: realImageViewSize)
centerImageView()
}
func centerImageView() {
let boundsSize = contentFrame.size
var imageViewFrame = imageView.frame
if imageViewFrame.size.width < boundsSize.width {
imageViewFrame.origin.x = (boundsSize.width - imageViewFrame.size.width) / 2.0
} else {
imageViewFrame.origin.x = 0.0
}
if imageViewFrame.size.height < boundsSize.height {
imageViewFrame.origin.y = (boundsSize.height - imageViewFrame.size.height) / 2.0
} else {
imageViewFrame.origin.y = 0.0
}
imageView.frame = imageViewFrame
}
// MARK: - Action
@objc func playButtonTouched(_ button: UIButton) {
guard let videoURL = image.videoURL else { return }
pageViewDelegate?.pageView(self, didTouchPlayButton: videoURL as URL)
}
}
// MARK: - LayoutConfigurable
extension PageView: LayoutConfigurable {
@objc func configureLayout() {
contentFrame = frame
contentSize = frame.size
imageView.frame = frame
zoomScale = minimumZoomScale
configureImageView()
}
}
// MARK: - UIScrollViewDelegate
extension PageView: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
centerImageView()
pageViewDelegate?.pageViewDidZoom(self)
}
}