Created
August 9, 2017 10:20
-
-
Save liamnichols/79bcb93852e11cdab7d7434aec6bd0b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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