123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- import UIKit
- protocol NCViewerImageCollectionViewCellDelegate: class {
- func didStartZooming(_ cell: NCViewerImageCollectionViewCell)
- }
- class NCViewerImageCollectionViewCell: UICollectionViewCell {
- static var reusableIdentifier: String = "NCViewerImageCollectionViewCell"
- private var dataTask: URLSessionDataTask?
- weak var delegate: NCViewerImageCollectionViewCellDelegate?
- @IBOutlet weak var imageWidthConstraint: NSLayoutConstraint!
- @IBOutlet weak var imageHeightConstraint: NSLayoutConstraint!
- @IBOutlet weak var topConstraint: NSLayoutConstraint!
- @IBOutlet weak var bottomConstraint: NSLayoutConstraint!
- @IBOutlet weak var scrollView: UIScrollView!
- @IBOutlet weak var galleryImageView: UIImageView!
- @IBOutlet weak var leadingConstraint: NSLayoutConstraint!
- @IBOutlet weak var trailingConstraint: NSLayoutConstraint!
- private var observer: NSKeyValueObservation?
- func withImageAsset(_ asset: NCViewerImageAsset?) {
- guard self.dataTask?.state != URLSessionDataTask.State.running else { return }
- guard let asset = asset else { return }
- if asset.image != nil {
- self.apply(image: self.fitIntoFrame(image: asset.image, type: asset.type))
- } else if asset.url != nil {
- self.galleryImageView.image = nil
- self.dataTask = asset.download(completion: { _ in
- self.apply(image: self.fitIntoFrame(image: asset.image, type: asset.type))
- })
- }
- }
- func apply(image: UIImage?) {
- guard let image = image else { return }
- self.galleryImageView.alpha = 0
- self.galleryImageView.image = image
- UIView.animate(withDuration: 0.1) {
- self.galleryImageView.alpha = 1
- }
- }
- override func draw(_ rect: CGRect) {
- super.draw(rect)
- self.scrollView.maximumZoomScale = 4
- self.redrawConstraintIfNeeded()
- self.observer = self.observe(\.bounds, options: NSKeyValueObservingOptions.new, changeHandler: { (_, _) in
- self.apply(image: self.fitIntoFrame(image: self.galleryImageView.image, type: nil))
- self.redrawConstraintIfNeeded()
- })
- }
- func cancelPendingDataTask() {
- self.dataTask?.cancel()
- }
- override func layoutSubviews() {
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
- self.redrawConstraintIfNeeded()
- }
- super.layoutSubviews()
- }
- override func prepareForReuse() {
- super.prepareForReuse()
- self.scrollView.setZoomScale(1, animated: false)
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
- // limitation of cell lifecycle
- self.redrawConstraintIfNeeded()
- }
- }
- func setMargins(vertical: CGFloat, horizontal: CGFloat) {
- self.topConstraint.constant = vertical
- self.bottomConstraint.constant = vertical
- self.leadingConstraint.constant = horizontal
- self.trailingConstraint.constant = horizontal
- }
- func redrawConstraintIfNeeded() {
- let imageHeight = self.galleryImageView.frame.size.height
- let imageWidth = self.galleryImageView.frame.size.width
- let spaceLeftVertical = self.scrollView.frame.size.height-imageHeight
- let spaceLeftHorizontal = self.scrollView.frame.size.width-imageWidth
- let constraintConstantValueVertical = spaceLeftVertical/2 > 0 ? spaceLeftVertical/2 : 0
- let constraintConstantValueHorizontal = spaceLeftHorizontal/2 > 0 ? spaceLeftHorizontal/2 : 0
- self.setMargins(vertical: constraintConstantValueVertical, horizontal: constraintConstantValueHorizontal)
- self.layoutIfNeeded()
- }
- private func fitIntoFrame(image: UIImage?, type: NCViewerImageAsset.ImageType?) -> UIImage? {
- let type: NCViewerImageAsset.ImageType = type ?? .jpg
- guard let image = image else { return nil }
- guard image.size != CGSize.zero else { return nil }
- let screenRatio = UIScreen.main.bounds.size.width/UIScreen.main.bounds.size.height
- var reqWidth: CGFloat = frame.size.width
- if image.size.width > reqWidth {
- reqWidth = image.size.width
- }
- let imageRatio = image.size.width/image.size.height
- if imageRatio < screenRatio {
- reqWidth = frame.size.height*imageRatio
- }
- let size = CGSize(width: reqWidth, height: reqWidth/imageRatio)
- if imageRatio < screenRatio {
- self.imageHeightConstraint.constant = frame.size.height
- self.imageWidthConstraint.constant = frame.size.height*imageRatio
- } else {
- self.imageHeightConstraint.constant = frame.size.width/imageRatio
- self.imageWidthConstraint.constant = frame.size.width
- }
- switch type {
- case .gif: return image
- case .jpg:
- UIGraphicsBeginImageContext(size)
- image.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
- let finalImage: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
- return finalImage
- }
- }
- func redrawImage() {
- self.apply(image: self.fitIntoFrame(image: self.galleryImageView.image, type: nil))
- self.redrawConstraintIfNeeded()
- }
- }
- extension NCViewerImageCollectionViewCell: UIScrollViewDelegate {
- func viewForZooming(in scrollView: UIScrollView) -> UIView? {
- return self.galleryImageView
- }
- func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
- self.delegate?.didStartZooming(self)
- }
- func scrollViewDidZoom(_ scrollView: UIScrollView) {
- self.redrawConstraintIfNeeded()
- }
- }
|