Skip to content

Instantly share code, notes, and snippets.

@liamnichols
Created August 9, 2017 10:20
Show Gist options
  • Save liamnichols/79bcb93852e11cdab7d7434aec6bd0b1 to your computer and use it in GitHub Desktop.
Save liamnichols/79bcb93852e11cdab7d7434aec6bd0b1 to your computer and use it in GitHub Desktop.
//
// GalleryItemCell.swift
// BrunchApp
//
// Created by Liam Nichols on 30/04/2017.
// Copyright © 2017 Bottomless Brunches. All rights reserved.
//
import UIKit
class GalleryItemCell: UICollectionViewCell {
@IBOutlet fileprivate var activityIndicatorView: UIActivityIndicatorView!
@IBOutlet fileprivate var scrollView: UIScrollView!
fileprivate let imageView = UIImageView()
private var imageLoadOperation: WebImageOperation?
override func awakeFromNib() {
super.awakeFromNib()
scrollView.addSubview(imageView)
}
override func prepareForReuse() {
super.prepareForReuse()
image = nil
}
func handleDoubleTap() {
UIView.animate(withDuration: 0.3) { [weak self] in
guard let scrollView = self?.scrollView else { return }
// If we have zoomed out fully, zoom in by 0.5x otherwise revert to zoomed out state
if scrollView.zoomScale == scrollView.minimumZoomScale {
scrollView.zoomScale += 0.5
} else {
scrollView.zoomScale = scrollView.minimumZoomScale
}
}
}
var imageState: GalleryTransitionController.SourceContext? {
guard let image = image else { return nil }
return GalleryTransitionController.SourceContext(
view: contentView,
rect: contentView.convert(imageView.frame, from: scrollView),
image: image)
}
var image: Image? {
didSet {
// Cancel any existing image loads and reset the state
imageLoadOperation?.cancel()
imageLoadOperation = nil
configureEmptyState(showActivity: false)
// Make sure we have an item that we want to load
guard let item = image else { return }
// If we have the source image cached then just use that and be dome
if let image = WebImageManager.shared.cachedImage(from: item.sourceURL) {
configurePopulatedState(with: image)
return
}
// Load the thumnail as a placeholder or just show blank depending on what we have
if let thumbnail = WebImageManager.shared.cachedImage(from: item.thumbnailURL) {
configurePopulatedState(with: thumbnail)
} else {
configureEmptyState(showActivity: true)
}
// Load the full resolution image
imageLoadOperation = WebImageManager.shared.loadImage(from: item.sourceURL) { [weak self] image, _ in
guard let `self` = self else { return }
if let image = image {
self.configurePopulatedState(with: image)
} else if self.activityIndicatorView.isAnimating {
self.configureEmptyState(showActivity: false)
}
}
}
}
private func configureEmptyState(showActivity: Bool = true) {
// Show or hide the activity indicator
if showActivity {
activityIndicatorView.startAnimating()
} else {
activityIndicatorView.stopAnimating()
}
// Clear the scroll view
imageView.image = nil
scrollView.contentSize = .zero
scrollView.zoomScale = 1.0
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 1.0
}
private func configurePopulatedState(with image: UIImage) {
// Stop the activity and unhide
activityIndicatorView.stopAnimating()
// Configure the image view
imageView.image = image
// Reset the content size
scrollView.zoomScale = 1.0
scrollView.contentSize = image.size
imageView.frame = CGRect(origin: .zero, size: image.size)
// Work out the smallest scale
let smallestScale = min(contentView.bounds.width / image.size.width,
contentView.bounds.height / image.size.height)
// Ensure all the zoom and positioning is correct
scrollView.maximumZoomScale = 2.0
scrollView.minimumZoomScale = smallestScale
scrollView.zoomScale = smallestScale
}
}
// MARK: - UIScrollViewDelegate
extension GalleryItemCell: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
// Work out the offsets
let offsetX = max((scrollView.bounds.width - scrollView.contentSize.width) * 0.5, 0.0)
let offsetY = max((scrollView.bounds.height - scrollView.contentSize.height) * 0.5, 0.0)
// Update the center
imageView.center = CGPoint(x: scrollView.contentSize.width * 0.5 + offsetX,
y: scrollView.contentSize.height * 0.5 + offsetY)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment