Skip to content

Instantly share code, notes, and snippets.

@gkye
Created July 3, 2017 23:41
Show Gist options
  • Save gkye/84192e67145d1bc72b287c82503eadb1 to your computer and use it in GitHub Desktop.
Save gkye/84192e67145d1bc72b287c82503eadb1 to your computer and use it in GitHub Desktop.
import Foundation
import UIKit
class ScrollingImageCell: UICollectionViewCell {
var imageView: UIImageView!
var scrollView: UIScrollView!
var doubleTapGesture: UITapGestureRecognizer!
var image: UIImage? {
didSet{
// setNeedsLayout()
guard let image = image else { return }
if image.size.height > image.size.width {
imageView.contentMode = .scaleAspectFill // Portrait
} else {
imageView.contentMode = .scaleAspectFit // Landscape
}
}
}
var topInset: CGFloat = 0 {
didSet {
centerIfNeeded()
}
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
scrollView = UIScrollView(frame: bounds)
imageView = UIImageView(frame: bounds)
imageView.contentMode = .scaleAspectFit
scrollView.addSubview(imageView)
scrollView.maximumZoomScale = 3
scrollView.delegate = self
scrollView.contentMode = .center
scrollView.showsHorizontalScrollIndicator = false
scrollView.showsVerticalScrollIndicator = false
scrollView.zoomScale = 1
if #available(iOS 9.0, *) {
scrollView.panGestureRecognizer.allowedTouchTypes = [ NSNumber(value:UITouchType.indirect.rawValue) ]
}
addSubview(scrollView)
doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(doubleTap(gr:)))
doubleTapGesture.numberOfTapsRequired = 2
addGestureRecognizer(doubleTapGesture)
}
func zoomRectForScale(scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero
zoomRect.size.height = imageView.frame.size.height / scale
zoomRect.size.width = imageView.frame.size.width / scale
let newCenter = imageView.convert(center, from: scrollView)
zoomRect.origin.x = newCenter.x - (zoomRect.size.width / 2.0)
zoomRect.origin.y = newCenter.y - (zoomRect.size.height / 2.0)
return zoomRect
}
@objc func doubleTap(gr: UITapGestureRecognizer) {
if scrollView.zoomScale == 1 {
scrollView.zoom(to: zoomRectForScale(scale: scrollView.maximumZoomScale, center: gr.location(in: gr.view)), animated: true)
} else {
scrollView.setZoomScale(1, animated: true)
}
}
override func layoutSubviews() {
super.layoutSubviews()
scrollView.frame = bounds
let size: CGSize
if let image = imageView.image {
let containerSize = CGSize(width: bounds.width, height: bounds.height - topInset)
if containerSize.width / containerSize.height < image.size.width / image.size.height {
size = CGSize(width: containerSize.width, height: containerSize.width * image.size.height / image.size.width )
} else {
size = CGSize(width: containerSize.height * image.size.width / image.size.height, height: containerSize.height )
}
} else {
size = CGSize(width: bounds.width, height: bounds.width)
}
imageView.frame = CGRect(origin: .zero, size: size)
scrollView.contentSize = size
centerIfNeeded()
}
// override func prepareForReuse() {
// super.prepareForReuse()
// scrollView.setZoomScale(1, animated: false)
// }
//
func centerIfNeeded() {
var inset = UIEdgeInsets(top: topInset, left: 0, bottom: 0, right: 0)
if scrollView.contentSize.height < scrollView.bounds.height - topInset {
let insetV = (scrollView.bounds.height - topInset - scrollView.contentSize.height)/2
inset.top += insetV
inset.bottom = insetV
}
if scrollView.contentSize.width < scrollView.bounds.width {
let insetV = (scrollView.bounds.width - scrollView.contentSize.width)/2
inset.left = insetV
inset.right = insetV
}
scrollView.contentInset = inset
}
}
extension ScrollingImageCell: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
centerIfNeeded()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment