Skip to content

Commit f4594e1

Browse files
authored
Merge pull request #44 from zfoltin/gallery-see-all
Gallery - See All - thumbnails FTW!
2 parents d285f54 + 45a18c7 commit f4594e1

11 files changed

+279
-48
lines changed

Example/ViewController.swift

+5-7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class ViewController: UIViewController {
2626
UIImage(named: "8"),
2727
UIImage(named: "9")]
2828

29+
var imageCount: Int {
30+
return images.count
31+
}
32+
2933
func provideImage(completion: UIImage? -> Void) {
3034
completion(UIImage(named: "image_big"))
3135
}
@@ -65,7 +69,7 @@ class ViewController: UIViewController {
6569
let headerView = CounterView(frame: frame, currentIndex: displacedView.tag, count: imageCount)
6670
let footerView = CounterView(frame: frame, currentIndex: displacedView.tag, count: imageCount)
6771

68-
let galleryViewController = GalleryViewController(imageProvider: imageProvider, displacedView: displacedView, imageCount: imageCount, startIndex: displacedView.tag, configuration: [.BackgroundColor(randomColorBackground())])
72+
let galleryViewController = GalleryViewController(imageProvider: imageProvider, displacedView: displacedView, imageCount: imageCount, startIndex: displacedView.tag)
6973

7074
galleryViewController.headerView = headerView
7175
galleryViewController.footerView = footerView
@@ -84,10 +88,4 @@ class ViewController: UIViewController {
8488

8589
self.presentImageGallery(galleryViewController)
8690
}
87-
88-
private func randomColorBackground() -> UIColor {
89-
let colors = [UIColor.whiteColor(), UIColor.blackColor()]
90-
let randomIndex = Int(arc4random_uniform(2))
91-
return colors[randomIndex]
92-
}
9391
}

ImageViewer.xcodeproj/project.pbxproj

+12
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
158A869B1D2E99F4004EE55E /* ThumbnailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158A869A1D2E99F4004EE55E /* ThumbnailsViewController.swift */; };
11+
158A869C1D2EA753004EE55E /* ThumbnailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158A869A1D2E99F4004EE55E /* ThumbnailsViewController.swift */; };
12+
158A869E1D2EC8CC004EE55E /* ThumbnailsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158A869D1D2EC8CC004EE55E /* ThumbnailsCell.swift */; };
13+
158A869F1D2EC8CC004EE55E /* ThumbnailsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 158A869D1D2EC8CC004EE55E /* ThumbnailsCell.swift */; };
1014
4CB66CD51C18772B002DB91F /* ImageViewerDismissTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB66CD41C18772B002DB91F /* ImageViewerDismissTransition.swift */; };
1115
4CB66CD61C18772B002DB91F /* ImageViewerDismissTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB66CD41C18772B002DB91F /* ImageViewerDismissTransition.swift */; };
1216
4CB66CD81C187F9C002DB91F /* ImageViewerSwipeToDismissTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CB66CD71C187F9C002DB91F /* ImageViewerSwipeToDismissTransition.swift */; };
@@ -62,6 +66,8 @@
6266
/* End PBXBuildFile section */
6367

6468
/* Begin PBXFileReference section */
69+
158A869A1D2E99F4004EE55E /* ThumbnailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailsViewController.swift; sourceTree = "<group>"; };
70+
158A869D1D2EC8CC004EE55E /* ThumbnailsCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailsCell.swift; sourceTree = "<group>"; };
6571
4CB66CD41C18772B002DB91F /* ImageViewerDismissTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageViewerDismissTransition.swift; sourceTree = "<group>"; };
6672
4CB66CD71C187F9C002DB91F /* ImageViewerSwipeToDismissTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageViewerSwipeToDismissTransition.swift; sourceTree = "<group>"; };
6773
4CD1C4981C160651008D5F84 /* ImageViewerPresentTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageViewerPresentTransition.swift; sourceTree = "<group>"; };
@@ -230,6 +236,7 @@
230236
isa = PBXGroup;
231237
children = (
232238
EBEBEF951C846847008C1E58 /* GalleryViewController.swift */,
239+
158A869A1D2E99F4004EE55E /* ThumbnailsViewController.swift */,
233240
);
234241
name = Controller;
235242
sourceTree = "<group>";
@@ -246,6 +253,7 @@
246253
isa = PBXGroup;
247254
children = (
248255
EB7B7E4D1C8F240D006834F7 /* HeaderFooterLayout.swift */,
256+
158A869D1D2EC8CC004EE55E /* ThumbnailsCell.swift */,
249257
);
250258
name = Layout;
251259
sourceTree = "<group>";
@@ -473,6 +481,7 @@
473481
EB40C3731C9C5BF1004EA215 /* UIViewController.swift in Sources */,
474482
EB5253F41C8DCE9800EAA4A4 /* CounterView.swift in Sources */,
475483
C7897CF41C1356C6006447FB /* ImageViewerController.swift in Sources */,
484+
158A869C1D2EA753004EE55E /* ThumbnailsViewController.swift in Sources */,
476485
4CB66CD81C187F9C002DB91F /* ImageViewerSwipeToDismissTransition.swift in Sources */,
477486
EB7B7E4F1C8F260A006834F7 /* HeaderFooterLayout.swift in Sources */,
478487
EB1CEBE51C846DEF00BB27B8 /* GalleryViewController.swift in Sources */,
@@ -481,6 +490,7 @@
481490
C7897CE71C1350B7006447FB /* ViewController.swift in Sources */,
482491
4CD1C49A1C16099B008D5F84 /* ImageViewerPresentTransition.swift in Sources */,
483492
EBA90E431C875225000AA697 /* ImageFadeInHandler.swift in Sources */,
493+
158A869E1D2EC8CC004EE55E /* ThumbnailsCell.swift in Sources */,
484494
4CD1C49C1C16FF64008D5F84 /* CGPoint.swift in Sources */,
485495
EBB390031C8C692800CE1F71 /* ImageViewControllerFactory.swift in Sources */,
486496
EB4DEBC01C84A6FD00D5F897 /* UIView.swift in Sources */,
@@ -502,6 +512,8 @@
502512
4CB66CD91C187F9C002DB91F /* ImageViewerSwipeToDismissTransition.swift in Sources */,
503513
EBA90E401C8729E2000AA697 /* GalleryPresentTransition.swift in Sources */,
504514
EB40C3781C9C5C48004EA215 /* ImageProvider.swift in Sources */,
515+
158A869F1D2EC8CC004EE55E /* ThumbnailsCell.swift in Sources */,
516+
158A869B1D2E99F4004EE55E /* ThumbnailsViewController.swift in Sources */,
505517
EB40C37E1C9C5E25004EA215 /* ImageViewerConfiguration.swift in Sources */,
506518
4CB66CD61C18772B002DB91F /* ImageViewerDismissTransition.swift in Sources */,
507519
EBEBEF941C84665B008C1E58 /* ImageViewController.swift in Sources */,

ImageViewer/Source/GalleryConfiguration.swift

+25-17
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,23 @@
99
import UIKit
1010

1111
public enum GalleryPagingMode {
12-
12+
1313
case Standard
1414
case Carousel
1515
}
1616

1717
public typealias GalleryConfiguration = [GalleryConfigurationItem]
1818

1919
public enum GalleryConfigurationItem {
20-
20+
2121
case ImageDividerWidth(CGFloat)
2222
case SpinnerStyle(UIActivityIndicatorViewStyle)
2323
case SpinnerColor(UIColor)
2424
case CloseButton(UIButton)
25+
case SeeAllButton(UIButton)
2526
case PagingMode(GalleryPagingMode)
26-
case CloseLayout(CloseButtonLayout)
27+
case CloseLayout(ButtonLayout)
28+
case SeeAllLayout(ButtonLayout)
2729
case HeaderViewLayout(HeaderLayout)
2830
case FooterViewLayout(FooterLayout)
2931
case StatusBarHidden(Bool)
@@ -32,26 +34,32 @@ public enum GalleryConfigurationItem {
3234
}
3335

3436
func defaultGalleryConfiguration() -> GalleryConfiguration {
35-
37+
3638
let dividerWidth = GalleryConfigurationItem.ImageDividerWidth(10)
3739
let spinnerColor = GalleryConfigurationItem.SpinnerColor(UIColor.whiteColor())
3840
let spinnerStyle = GalleryConfigurationItem.SpinnerStyle(UIActivityIndicatorViewStyle.White)
39-
40-
let button = UIButton(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 50, height: 50)))
41-
button.setImage(UIImage(named: "close_normal"), forState: UIControlState.Normal)
42-
button.setImage(UIImage(named: "close_highlighted"), forState: UIControlState.Highlighted)
43-
let closeButton = GalleryConfigurationItem.CloseButton(button)
44-
41+
42+
let closeButton = UIButton(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 50, height: 50)))
43+
closeButton.setImage(UIImage(named: "close_normal"), forState: UIControlState.Normal)
44+
closeButton.setImage(UIImage(named: "close_highlighted"), forState: UIControlState.Highlighted)
45+
let closeButtonConfig = GalleryConfigurationItem.CloseButton(closeButton)
46+
47+
let seeAllButton = UIButton(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 100, height: 50)))
48+
seeAllButton.setTitle("See All", forState: .Normal)
49+
let seeAllButtonConfig = GalleryConfigurationItem.SeeAllButton(seeAllButton)
50+
4551
let pagingMode = GalleryConfigurationItem.PagingMode(GalleryPagingMode.Standard)
46-
47-
let closeLayout = GalleryConfigurationItem.CloseLayout(CloseButtonLayout.PinRight(8, 16))
52+
53+
let closeLayout = GalleryConfigurationItem.CloseLayout(ButtonLayout.PinRight(8, 16))
54+
let seeAllLayout = GalleryConfigurationItem.CloseLayout(ButtonLayout.PinLeft(8, 16))
4855
let headerLayout = GalleryConfigurationItem.HeaderViewLayout(HeaderLayout.Center(25))
4956
let footerLayout = GalleryConfigurationItem.FooterViewLayout(FooterLayout.Center(25))
50-
57+
5158
let statusBarHidden = GalleryConfigurationItem.StatusBarHidden(true)
52-
59+
5360
let hideDecorationViews = GalleryConfigurationItem.HideDecorationViewsOnLaunch(true)
54-
61+
5562
let backgroundColor = GalleryConfigurationItem.BackgroundColor(.blackColor())
56-
return [dividerWidth, spinnerStyle, spinnerColor, closeButton, pagingMode, headerLayout, footerLayout, closeLayout, statusBarHidden, hideDecorationViews, backgroundColor]
57-
}
63+
64+
return [dividerWidth, spinnerStyle, spinnerColor, closeButtonConfig, seeAllButtonConfig, pagingMode, headerLayout, footerLayout, closeLayout, seeAllLayout, statusBarHidden, hideDecorationViews, backgroundColor]
65+
}

ImageViewer/Source/GalleryViewController.swift

+77-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
1212

1313
/// UI
1414
private var closeButton: UIButton?
15+
private var seeAllButton: UIButton?
1516
/// You can set any UIView subclass here. If set, it will be integrated into view hierachy and laid out
1617
/// following either the default pinning settings or settings from a custom configuration.
1718
public var headerView: UIView?
@@ -47,7 +48,8 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
4748
private let toggleHeaderFooterAnimationDuration = 0.15
4849
private let closeAnimationDuration = 0.2
4950
private let rotationAnimationDuration = 0.2
50-
private var closeLayout = CloseButtonLayout.PinRight(25, 16)
51+
private var closeLayout = ButtonLayout.PinLeft(8, 16)
52+
private var seeAllLayout = ButtonLayout.PinRight(8, 16)
5153
private var headerLayout = HeaderLayout.Center(25)
5254
private var footerLayout = FooterLayout.Center(25)
5355
private var statusBarHidden = true
@@ -92,10 +94,12 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
9294
case .SpinnerStyle(let style): spinnerStyle = style
9395
case .SpinnerColor(let color): spinnerColor = color
9496
case .CloseButton(let button): closeButton = button
97+
case .SeeAllButton(let button): seeAllButton = button
9598
case .PagingMode(let mode): galleryPagingMode = mode
9699
case .HeaderViewLayout(let layout): headerLayout = layout
97100
case .FooterViewLayout(let layout): footerLayout = layout
98101
case .CloseLayout(let layout): closeLayout = layout
102+
case .SeeAllLayout(let layout): seeAllLayout = layout
99103
case .StatusBarHidden(let hidden): statusBarHidden = hidden
100104
case .HideDecorationViewsOnLaunch(let hidden): isDecorationViewsHidden = hidden
101105
case .BackgroundColor(let color): backgroundColor = color
@@ -180,7 +184,7 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
180184

181185
func configureInitialImageController() {
182186

183-
let initialImageController = ImageViewController(imageProvider: imageProvider, configuration: configuration, imageCount: imageCount, displacedView: displacedView, startIndex: startIndex, imageIndex: startIndex, showDisplacedImage: true, fadeInHandler: fadeInHandler, delegate: self)
187+
let initialImageController = self.imageControllerFactory.createImageViewController(startIndex)
184188
self.setViewControllers([initialImageController], direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
185189
initialImageController.view.hidden = true
186190

@@ -195,13 +199,21 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
195199

196200
closeButton?.addTarget(self, action: #selector(GalleryViewController.interactiveClose), forControlEvents: .TouchUpInside)
197201
}
198-
202+
203+
private func configureSeeAllButton() {
204+
205+
seeAllButton?.addTarget(self, action: #selector(GalleryViewController.seeAll), forControlEvents: .TouchUpInside)
206+
}
207+
199208
func createViewHierarchy() {
200209

201210
if let close = closeButton {
202-
203211
self.view.addSubview(close)
204212
}
213+
214+
if let seeAllButton = seeAllButton {
215+
self.view.addSubview(seeAllButton)
216+
}
205217
}
206218

207219
func configureHeaderView() {
@@ -223,6 +235,7 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
223235
self.presentTransition.headerView = self.headerView
224236
self.presentTransition.footerView = self.footerView
225237
self.presentTransition.closeView = self.closeButton
238+
self.presentTransition.seeAllView = self.seeAllButton
226239
}
227240

228241
public override func viewDidLoad() {
@@ -231,6 +244,7 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
231244
configureHeaderView()
232245
configureFooterView()
233246
configureCloseButton()
247+
configureSeeAllButton()
234248
configurePresentTransition()
235249
createViewHierarchy()
236250
}
@@ -241,6 +255,7 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
241255
super.viewDidLayoutSubviews()
242256

243257
layoutCloseButton()
258+
layoutSeeAll()
244259
layoutHeaderView()
245260
layoutFooterView()
246261
}
@@ -264,7 +279,23 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
264279
close.frame.origin.y = marginTop
265280
}
266281
}
267-
282+
283+
func layoutSeeAll() {
284+
285+
guard let seeAllButton = seeAllButton else { return }
286+
287+
switch seeAllLayout {
288+
case .PinRight(let marginTop, let marginRight):
289+
seeAllButton.autoresizingMask = [.FlexibleBottomMargin, .FlexibleLeftMargin]
290+
seeAllButton.frame.origin.x = self.view.bounds.size.width - marginRight - seeAllButton.bounds.size.width
291+
seeAllButton.frame.origin.y = marginTop
292+
case .PinLeft(let marginTop, let marginLeft):
293+
seeAllButton.autoresizingMask = [.FlexibleBottomMargin, .FlexibleRightMargin]
294+
seeAllButton.frame.origin.x = marginLeft
295+
seeAllButton.frame.origin.y = marginTop
296+
}
297+
}
298+
268299
func layoutHeaderView() {
269300

270301
guard let header = headerView else { return }
@@ -349,14 +380,52 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
349380

350381
closeWithAnimation(closedCompletion)
351382
}
352-
383+
384+
func seeAll() {
385+
let seeAllController = ThumbnailsViewController(imageProvider: self.imageProvider)
386+
let closeButton = UIButton(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: 50, height: 50)))
387+
closeButton.setImage(UIImage(named: "close_normal"), forState: UIControlState.Normal)
388+
closeButton.setImage(UIImage(named: "close_highlighted"), forState: UIControlState.Highlighted)
389+
seeAllController.closeButton = closeButton
390+
seeAllController.closeLayout = closeLayout
391+
seeAllController.onItemSelected = { index in
392+
self.goToIndex(index)
393+
}
394+
presentViewController(seeAllController, animated: true, completion: nil)
395+
}
396+
397+
public func goToIndex(index: Int) {
398+
guard currentIndex != index && index >= 0 && index < imageCount else { return }
399+
400+
let imageViewController = self.imageControllerFactory.createImageViewController(index)
401+
let direction: UIPageViewControllerNavigationDirection = index > currentIndex ? .Forward : .Reverse
402+
403+
// workaround to make UIPageViewController happy
404+
if direction == .Forward {
405+
let previousVC = self.imageControllerFactory.createImageViewController(index - 1)
406+
setViewControllers([previousVC], direction: direction, animated: true, completion: { finished in
407+
dispatch_async(dispatch_get_main_queue(), { [weak self] in
408+
self?.setViewControllers([imageViewController], direction: direction, animated: false, completion: nil)
409+
})
410+
})
411+
} else {
412+
let nextVC = self.imageControllerFactory.createImageViewController(index + 1)
413+
setViewControllers([nextVC], direction: direction, animated: true, completion: { finished in
414+
dispatch_async(dispatch_get_main_queue(), { [weak self] in
415+
self?.setViewControllers([imageViewController], direction: direction, animated: false, completion: nil)
416+
})
417+
})
418+
}
419+
}
420+
353421
func closeWithAnimation(completion: (() -> Void)?) {
354422

355423
UIView.animateWithDuration(0.1, animations: { [weak self] in
356424

357425
self?.headerView?.alpha = 0.0
358426
self?.footerView?.alpha = 0.0
359427
self?.closeButton?.alpha = 0.0
428+
self?.seeAllButton?.alpha = 0.0
360429

361430
}) { [weak self] done in
362431

@@ -399,6 +468,7 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
399468
let alpha = 1 - distance * swipeToDismissFadeOutAccelerationFactor
400469

401470
closeButton?.alpha = alpha
471+
seeAllButton?.alpha = alpha
402472
headerView?.alpha = alpha
403473
footerView?.alpha = alpha
404474
}
@@ -415,7 +485,7 @@ final public class GalleryViewController : UIPageViewController, UIViewControlle
415485
self?.headerView?.alpha = alpha
416486
self?.footerView?.alpha = alpha
417487
self?.closeButton?.alpha = alpha
418-
488+
self?.seeAllButton?.alpha = alpha
419489
})
420490
}
421491

ImageViewer/Source/GalleryViewControllerDatasource.swift

-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ final class GalleryViewControllerDatasource: NSObject, UIPageViewControllerDataS
1919
self.imageControllerFactory = imageControllerFactory
2020
self.imageCount = imageCount
2121
self.galleryPagingMode = (imageCount > 1) ? galleryPagingMode : GalleryPagingMode.Standard
22-
23-
UIDevice.currentDevice().orientation
2422
}
2523

2624
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {

ImageViewer/Source/HeaderFooterLayout.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public typealias MarginTop = CGFloat
1414
public typealias MarginBottom = CGFloat
1515

1616
/// Represents possible layouts for the close button
17-
public enum CloseButtonLayout {
17+
public enum ButtonLayout {
1818

1919
case PinLeft(MarginTop, MarginLeft)
2020
case PinRight(MarginTop, MarginRight)

ImageViewer/Source/ImageProvider.swift

+3-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import UIKit
1010

1111
// allows very loose coupling of the image source and the gallery. You make whatever object conform to this protocol and pass a reference to youur object to the viewer. the viwer will at convenient times ask this object for an image (at index).
1212
public protocol ImageProvider {
13-
13+
14+
var imageCount: Int { get }
1415
func provideImage(completion: UIImage? -> Void)
1516
func provideImage(atIndex index: Int, completion: UIImage? -> Void)
16-
}
17+
}

0 commit comments

Comments
 (0)