Skip to content

Commit

Permalink
Merge pull request #18 from Raizlabs/feature/ateliercw/Add_activity_i…
Browse files Browse the repository at this point in the history
…ndicator_view

added activity indicator view
  • Loading branch information
Michael Skiba authored Jan 6, 2017
2 parents eaf8097 + 7b88105 commit f4a6704
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 59 deletions.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ func createPhotoGallery() -> RIGImageGalleryViewController {
"https://placehold.it/150x350",
].flatMap(URL.init(string:))

let rigItems = urls.map { _ in
RIGImageGalleryItem(placeholderImage: UIImage(named: "placeholder"))
let rigItems: [RIGImageGalleryItem] = urls.map { _ in
RIGImageGalleryItem(placeholderImage: UIImage(named: "placeholder") ?? UIImage(),
isLoading: true)
}

let rigController = RIGImageGalleryViewController(images: rigItems)
Expand All @@ -71,6 +72,7 @@ func createPhotoGallery() -> RIGImageGalleryViewController {
let request = imageSession.dataTask(with: URLRequest(url: URL)) { [weak rigController] data, _, error in
if let image = data.flatMap(UIImage.init), error == nil {
rigController?.images[index].image = image
rigController?.images[index].isLoading = false
}
}
request.resume()
Expand Down
65 changes: 37 additions & 28 deletions RIGImageGallery/RIGAutoCenteringScrollView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,48 @@

import UIKit

class RIGAutoCenteringScrollView: UIScrollView {
open class RIGAutoCenteringScrollView: UIScrollView {

var allowZoom: Bool = false
internal var allowZoom: Bool = false

var baseInsets: UIEdgeInsets = UIEdgeInsets() {
internal var baseInsets: UIEdgeInsets = UIEdgeInsets() {
didSet {
updateZoomScale(preserveScale: true)
}
}

var zoomImage: UIImage? {
open var zoomImage: UIImage? {
didSet {
if oldValue === zoomImage {
return
}
if let img = zoomImage {
let imageView: UIImageView
if let img = contentView {
imageView = img
}
else {
imageView = UIImageView()
contentView = imageView
addSubview(imageView)
}
imageView.frame = CGRect(origin: CGPoint(), size: img.size)
imageView.image = img
contentView.isHidden = false
contentView.image = img
}
else {
contentView?.removeFromSuperview()
contentView = nil
contentView.isHidden = true
}
updateZoomScale(preserveScale: false)
}
}

fileprivate var contentView: UIImageView?
fileprivate var contentView = UIImageView()

override init(frame: CGRect) {
public override init(frame: CGRect) {
super.init(frame: frame)
showsVerticalScrollIndicator = false
showsHorizontalScrollIndicator = false
addSubview(contentView)
configureConstraints()
delegate = self
}

required init?(coder aDecoder: NSCoder) {
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override var frame: CGRect {
open override var frame: CGRect {
didSet {
updateZoomScale(preserveScale: true)
}
Expand All @@ -68,18 +60,30 @@ class RIGAutoCenteringScrollView: UIScrollView {
extension RIGAutoCenteringScrollView {

func toggleZoom(animated: Bool = true) {
if zoomScale != minimumZoomScale {
setZoomScale(minimumZoomScale, animated: animated)
}
else {
setZoomScale(maximumZoomScale, animated: animated)
if self.isUserInteractionEnabled {
if zoomScale != minimumZoomScale {
setZoomScale(minimumZoomScale, animated: animated)
}
else {
setZoomScale(maximumZoomScale, animated: animated)
}
}
}

}

private extension RIGAutoCenteringScrollView {

func configureConstraints() {
contentView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
contentView.topAnchor.constraint(equalTo: topAnchor),
contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
])
}

func updateZoomScale(preserveScale: Bool) {
guard let image = zoomImage else {
contentSize = frame.size
Expand All @@ -88,6 +92,8 @@ private extension RIGAutoCenteringScrollView {
setZoomScale(1, animated: false)
return
}
updateConstraintsIfNeeded()
layoutIfNeeded()

let adjustedFrame = UIEdgeInsetsInsetRect(frame, baseInsets)

Expand Down Expand Up @@ -137,17 +143,20 @@ private extension RIGAutoCenteringScrollView {
}

contentInset = UIEdgeInsets(top: vertical + baseInsets.top, left: horizontal + baseInsets.left, bottom: vertical + baseInsets.bottom, right: horizontal + baseInsets.right)

updateConstraintsIfNeeded()
layoutIfNeeded()
}

}

extension RIGAutoCenteringScrollView: UIScrollViewDelegate {

func viewForZooming(in scrollView: UIScrollView) -> UIView? {
open func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return allowZoom ? contentView : nil
}

func scrollViewDidZoom(_ scrollView: UIScrollView) {
open func scrollViewDidZoom(_ scrollView: UIScrollView) {
centerContent()
}

Expand Down
5 changes: 4 additions & 1 deletion RIGImageGallery/RIGImageGalleryItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ public struct RIGImageGalleryItem: Equatable {
public var placeholderImage: UIImage?
/// The title of the image
public var title: String?
// The loading state
public var isLoading: Bool

public init(image: UIImage? = nil, placeholderImage: UIImage? = nil, title: String? = nil) {
public init(image: UIImage? = nil, placeholderImage: UIImage? = nil, title: String? = nil, isLoading: Bool = false) {
self.image = image
self.placeholderImage = placeholderImage
self.title = title
self.isLoading = isLoading
}

}
Expand Down
22 changes: 14 additions & 8 deletions RIGImageGallery/RIGImageGalleryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import UIKit

open class RIGImageGalleryViewController: UIPageViewController {

public typealias GalleryPositionUpdateHandler = (_ gallery: RIGImageGalleryViewController, _ position: Int, _ total: Int) -> ()
public typealias ActionButtonPressedHandler = (_ gallery: RIGImageGalleryViewController, _ item: RIGImageGalleryItem) -> ()
public typealias GalleryEventHandler = (RIGImageGalleryViewController) -> ()
public typealias IndexUpdateHandler = (Int) -> ()
public typealias GalleryPositionUpdateHandler = (_ gallery: RIGImageGalleryViewController, _ position: Int, _ total: Int) -> Void
public typealias ActionButtonPressedHandler = (_ gallery: RIGImageGalleryViewController, _ item: RIGImageGalleryItem) -> Void
public typealias GalleryEventHandler = (RIGImageGalleryViewController) -> Void
public typealias IndexUpdateHandler = (Int) -> Void

/// An optional closure to execute if the action button is tapped
open var actionButtonHandler: ActionButtonPressedHandler?
Expand Down Expand Up @@ -181,6 +181,14 @@ open class RIGImageGalleryViewController: UIPageViewController {
traitCollectionChangeHandler?(self)
}

/// Allows subclasses of RIGImageGallery to customize the gallery page
///
/// - Parameter viewerItem: The item to be displayed
/// - Returns: The view controller that will display the item
open func createNewPage(for viewerItem: RIGImageGalleryItem) -> UIViewController {
return RIGSingleImageViewController(viewerItem: viewerItem)
}

}

extension RIGImageGalleryViewController: UIGestureRecognizerDelegate {
Expand Down Expand Up @@ -237,16 +245,14 @@ extension RIGImageGalleryViewController: UIPageViewControllerDataSource {
guard let index = indexOf(viewController: viewController), index < images.count - 1 else {
return nil
}
let zoomView = RIGSingleImageViewController(viewerItem: images[index + 1])
return zoomView
return createNewPage(for: images[index + 1])
}

public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let index = indexOf(viewController: viewController), index > 0 else {
return nil
}
let zoomView = RIGSingleImageViewController(viewerItem: images[index - 1])
return zoomView
return createNewPage(for: images[index + -1])
}

}
Expand Down
60 changes: 49 additions & 11 deletions RIGImageGallery/RIGSingleImageViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,52 @@

import UIKit

class RIGSingleImageViewController: UIViewController {
open class RIGSingleImageViewController: UIViewController {

var viewerItem: RIGImageGalleryItem? {
open var viewerItem: RIGImageGalleryItem? {
didSet {
viewerItemUpdated()
}
}

let scrollView = RIGAutoCenteringScrollView()
open let scrollView = RIGAutoCenteringScrollView()
open var activityIndicator: UIActivityIndicatorView? {
didSet {
oldValue?.removeFromSuperview()
if let newValue = activityIndicator {
view.addSubview(newValue)
NSLayoutConstraint.activate([
newValue.centerXAnchor.constraint(equalTo: view.layoutMarginsGuide.centerXAnchor),
newValue.centerYAnchor.constraint(equalTo: view.layoutMarginsGuide.centerYAnchor),
])
}
}
}

convenience init(viewerItem: RIGImageGalleryItem) {
public convenience init(viewerItem: RIGImageGalleryItem) {
self.init()
self.viewerItem = viewerItem
viewerItemUpdated()
}

override func loadView() {
open override func viewDidLoad() {
super.viewDidLoad()
automaticallyAdjustsScrollViewInsets = false
view = scrollView
view.backgroundColor = .black
view.clipsToBounds = true
view.addSubview(scrollView)
let indicatorView = UIActivityIndicatorView()
indicatorView.activityIndicatorViewStyle = .gray
indicatorView.hidesWhenStopped = true
self.activityIndicator = indicatorView
configureConstraints()
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
viewerItemUpdated()
}

override func viewDidDisappear(_ animated: Bool) {
open override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: true)
}
Expand All @@ -45,8 +63,28 @@ class RIGSingleImageViewController: UIViewController {
private extension RIGSingleImageViewController {

func viewerItemUpdated() {
if viewerItem?.isLoading == true && activityIndicator?.isAnimating == false {
activityIndicator?.startAnimating()
}
else if viewerItem?.isLoading == false && activityIndicator?.isAnimating == true {
activityIndicator?.stopAnimating()
}
scrollView.allowZoom = viewerItem?.image != nil
scrollView.zoomImage = viewerItem?.image ?? viewerItem?.placeholderImage
scrollView.isUserInteractionEnabled = viewerItem?.isLoading == false
if !view.frame.isEmpty {
scrollView.zoomImage = viewerItem?.image ?? viewerItem?.placeholderImage
}
scrollView.setZoomScale(scrollView.minimumZoomScale, animated: false)
}

func configureConstraints() {
scrollView.translatesAutoresizingMaskIntoConstraints = false
activityIndicator?.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
])
}
}
21 changes: 12 additions & 9 deletions RIGImageGalleryDemo/View Controller/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,27 +107,31 @@ private extension ViewController {

let urls = type(of: self).urls

let rigItems = urls.map { _ in
RIGImageGalleryItem(placeholderImage: UIImage(named: "placeholder") ?? UIImage())
let rigItems: [RIGImageGalleryItem] = urls.map { url in
RIGImageGalleryItem(placeholderImage: #imageLiteral(resourceName: "placeholder"),
title: url.pathComponents.last ?? "",
isLoading: true)
}

let rigController = RIGImageGalleryViewController(images: rigItems)

for (index, URL) in urls.enumerated() {
for (index, URL) in urls.enumerated() {
let completion = rigController.handleImageLoadAtIndex(index)
let request = imageSession.dataTask(with: URLRequest(url: URL), completionHandler: completion)
let request = imageSession.dataTask(with: URLRequest(url: URL),
completionHandler: completion)
request.resume()
}

rigController.setCurrentImage(2, animated: false)

return rigController
}

func prepareLocalGallery() -> RIGImageGalleryViewController {

let items: [UIImage] = ["1", "2", "3", "4", "5", "6"].flatMap(UIImage.init(named:))

let rigItems = items.map { item in
let rigItems: [RIGImageGalleryItem] = items.map { item in
RIGImageGalleryItem(image: item)
}

Expand All @@ -148,17 +152,16 @@ private extension ViewController {
}

private extension RIGImageGalleryViewController {
func handleImageLoadAtIndex(_ index: Int) -> ((Data?, URLResponse?, Error?) -> ()) {
func handleImageLoadAtIndex(_ index: Int) -> ((Data?, URLResponse?, Error?) -> Void) {
return { [weak self] (data: Data?, response: URLResponse?, error: Error?) in
guard let image = data.flatMap(UIImage.init), error == nil else {
if let error = error {
print(error)
}
return
}
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self?.images[index].image = image
}
self?.images[index].isLoading = false
self?.images[index].image = image
}
}
}

0 comments on commit f4a6704

Please sign in to comment.