263 Commits

Author SHA1 Message Date
Khoa Pham eb4b12f633 Bump 1.1.0 2017-10-03 13:34:07 +02:00
Khoa Pham c00d8b62dd Update demo 2017-10-03 13:31:18 +02:00
Khoa Pham 0d60426da2 Lock to 2.0 2017-10-03 13:28:30 +02:00
Khoa Pham fec46dbd52 Merge pull request #138 from TParizek/master
Specified Hue dependency version in podspec - Issue 137
2017-10-03 13:26:01 +02:00
Tomáš Pařízek 54da63c4a1 Specified Hue dependency version in podspec 2017-10-02 14:16:02 +02:00
Christoffer Winterkvist ec1200faea Merge pull request #129 from r-mckay/feature/useSwiftLint
project: use swiftlint and fix triggered warnings
2017-09-03 14:32:32 +02:00
Romain Bertozzi f0825e09d5 source: fix SwiftLint unused closure parameters
This commit fixes several warnings concerning unused closure parameters.
2017-09-02 12:23:47 -04:00
Romain Bertozzi 1e354c2675 source: fix SwiftLint option redondant init
This commit fixes a SwiftLint Option Redondant Initialization warning in
a file.
2017-09-02 12:19:36 -04:00
Romain Bertozzi eade5ac4c8 source: fix SwiftLint colon violation
This commit takes care of fixing a SwiftLint Colon Violation in a file.
2017-09-02 12:19:36 -04:00
Romain Bertozzi 8a33f9529b source: fix SwiftLint parameter alignement violation
This commit aligns parameters in a call to fix a SwiftLint warning.
2017-09-02 12:19:36 -04:00
Romain Bertozzi 4abeb93ac7 source: remove trailing spaces
This commit solves the SwiftLint warning concerning the trailing spaces.
2017-09-02 12:19:36 -04:00
Romain Bertozzi 619f84d89e project: add build phase running SwiftLint
This commit adds a build phase to the project to run SwiftLint. This new
phase follows the implementation made in the ImagePicker project [1].

This commit does not try to handle the eventual warning that could be
raised by the static code analysis.

[1] https://github.com/hyperoslo/ImagePicker
2017-09-02 12:19:36 -04:00
Christoffer Winterkvist 9531315c94 Merge pull request #123 from ShaneQi/fix_hide_status_bar_and_footer_gradient
Fixed two bugs.
2017-09-01 09:03:37 +02:00
Vadym Markov cfafbbcb14 Merge pull request #127 from r-mckay/fix/resolveWarning
lightboxController: fix warning
2017-08-27 19:40:37 +02:00
Shane Qi 6a6096e0b8 Fixed footer view gradient.
Should remove gradient layer if infoLabel's text is empty, regardless expanded state.

This is a override commit, in order to run CI again.
2017-08-26 19:54:37 -05:00
Romain Bertozzi 1480a44dfb lightboxController: fix warning
This commit fixes a warning indicating that a variable value was never
mutated and should be a constant.

To fix this warning we actually replace the 'var' by a 'let'.
2017-08-26 17:45:00 -04:00
Christoffer Winterkvist 2687d175c1 Merge pull request #128 from r-mckay/fix/continuousIntegration
project: update continuous integration setup
2017-08-26 13:51:32 +02:00
Romain Bertozzi c84682d3d9 project: update continuous integration setup
This commit updates the continuous integration setup by selecting the
Xcode 8.3 osx_image and by indicating that the project is written in
swift.
2017-08-25 16:12:33 -04:00
Shane Qi 6627936d23 Fixed status bar hidden config.
Switched from `UIApplication.shared.setStatusBarHidden` to `prefersStatusBarHidden`.
2017-07-13 18:06:38 -05:00
onmyway133 b26ee135bc Merge pull request #120 from vitalii-tym/fix/issue108
Updating the image frames while images are still being loaded
2017-06-20 15:11:00 +02:00
onmyway133 96d7da82bb Merge pull request #119 from vitalii-tym/fix/issue117
Cutting long texts quicker
2017-06-20 15:07:01 +02:00
onmyway133 9707c7cfe4 Merge pull request #122 from vitalii-tym/improvement/accessible-images
Updating the .image property of a LightboxImage instance after Lightbox has downloaded an image via URL
2017-06-20 11:31:28 +02:00
Vitaliy Tim 4968853f8c Made image property of LightBox images accessible after the image has been loaded via URL 2017-06-20 11:29:48 +03:00
Vitaliy Tim 053735d408 Properly updating the image frames while images are still being loaded, so that activity indicators are correcty shown 2017-06-20 10:59:38 +03:00
Vitaliy Tim 6052398040 Speeding up cutting process for long texts 2017-06-20 10:39:18 +03:00
onmyway133 df48ce7b85 Merge pull request #112 from danwilliams64/fix/screen_bounds
Use key window bounds instead of screen bounds
2017-06-19 12:46:00 +02:00
Dan Williams eb44646978 Use app delegate's window instead of screen bounds 2017-06-19 11:30:35 +01:00
onmyway133 6686d8f83b Merge pull request #113 from vitalii-tym/master
Preserve correct Navigation Bar after dismissal when opened from a controller with a Nav Bar
2017-06-19 11:30:30 +02:00
Vitaliy Tim 03be7479f4 Fixes an issue with Navigation Bar, which had wrong position after the lightbox has been dismissed 2017-06-19 11:50:09 +03:00
Christoffer Winterkvist 3b54e8959d Merge pull request #107 from hyperoslo/improve/dynamic-background
Fix dynamic background loading
2017-04-25 12:33:20 +02:00
Christoffer Winterkvist 69813ee7fe Fix dynamic background loading
Because `loadDynamicBackground` is called in `remoteImageDidLoad`, it
can end up flickering between all images as they are loaded from the
network. To fix this issue there is a now a small safeguard in
`remoteImageDidLoad` to evaluate if the image view is on screen,
otherwise just return early and don't switch out the background.

The `PageViewDelegate` has been slightly modified to return the image
view when loading remote images, that image view is used in the safe
guard mentioned earlier.

The `addìmageTo` now uses a weak reference to reduce the chance of
holding reference.

`addGradientLayer` now uses `@discardableResult` so that you don't have
to assign it to a variable when using the method.

The `goTo` method in `LightboxController` will no disregard the
animation if the controller is not on screen. This is done by checking
if the controller's view as a window or not.
2017-04-25 07:28:13 +02:00
Vadym Markov 4ccab620d6 Merge pull request #104 from rmnblm/master
Auto-size Close and Delete buttons
2017-04-21 09:37:55 +02:00
Roman Blum 3ea5a88e01 change 4 spaces to 2 spaces 2017-04-21 09:36:51 +02:00
Roman Blum 2b9216b1b8 auto-size Close and Delete buttons 2017-03-14 09:26:02 +01:00
Khoa Pham 48f307b003 Merge pull request #103 from rmnblm/master
Fix half-black screen after dismissal
2017-03-02 15:00:16 +01:00
Roman Blum eb44c67f69 Fix half-black screen after dismissal 2017-03-02 12:06:42 +01:00
John Sundell e6452f116e Merge pull request #94 from basecom/master
Added new protocol LightboxControllerTouchDelegate
2017-02-14 09:56:02 +01:00
Christoph Dieckmann 96c660a424 Added new protocol LightboxControllerTouchDelegate to delegate the touch event to the calling object. 2017-02-07 14:35:16 +01:00
Vadym Markov 4833dcde35 Update README.md 2016-12-21 15:17:16 +01:00
Vadym Markov 8f907c1fe9 Update README.md 2016-12-21 15:10:40 +01:00
Vadym Markov e314fea3e7 Update summary 2016-12-21 14:36:07 +01:00
Vadym Markov b4ec75ca27 Add swift version 2016-12-21 14:34:18 +01:00
Vadym Markov f483716859 Merge pull request #91 from hyperoslo/rename/example
Rename Demo to Example
2016-12-21 14:29:40 +01:00
Vadym Markov 83397dc491 Rename Demo to Example 2016-12-21 14:29:17 +01:00
Vadym Markov f2319d70f8 Update Lightbox.podspec 2016-12-21 14:24:59 +01:00
Christoffer Winterkvist 2d03d8a7e1 Merge pull request #87 from hyperoslo/swift-3
Swift 3
2016-12-21 14:19:23 +01:00
Vadym Markov 04437d8450 Add icon to readme 2016-12-21 14:16:45 +01:00
Vadym Markov d31d74d0b5 Resolve conflicts 2016-12-21 14:15:01 +01:00
Christoffer Winterkvist 40730ff2c5 Merge pull request #86 from hyperoslo/feature/readme
Feature/readme
2016-12-19 15:05:40 +01:00
Vadym Markov fa965b8a15 Fix typos 2016-12-19 14:57:14 +01:00
Vadym Markov 90c8c87565 Remove links 2016-12-19 14:20:39 +01:00
Vadym Markov dbac1b89e3 Add readme 2016-12-19 14:01:42 +01:00
Vadym Markov 770af6fcdc Update demo 2016-12-19 14:01:34 +01:00
Vadym Markov c1be7f8d71 Carthage update 2016-12-19 14:01:21 +01:00
Christoffer Winterkvist c8a2b2be8a Merge pull request #85 from hyperoslo/fix/dismiss_controls
Hide controls upon single tap
2016-12-11 17:34:18 +01:00
Khoa Pham b525124b3e Add Lightbox.bundle 2016-12-09 21:37:59 +01:00
Khoa Pham a74e9ff7ee Add single tap gesture recognizer 2016-12-09 16:42:46 +01:00
Khoa Pham 40f6bd91c7 Run pod install 2016-12-09 15:46:27 +01:00
Khoa Pham e465067217 Merge pull request #84 from hyperoslo/fix/resources
Move image files into Resources folder
2016-11-10 12:51:18 +01:00
Hyperseed 002dd5558b Update resource path 2016-11-10 12:51:06 +01:00
Hyperseed cfacb850f9 Move image files into Resources folder 2016-11-10 12:44:23 +01:00
Khoa Pham 98e3f62ebe Remove Sugar 2016-10-17 10:52:21 +02:00
Khoa Pham b6d1a36ee5 Use white indicator view 2016-10-17 10:42:20 +02:00
Khoa Pham 345bbd55b3 Update demo 2016-10-17 10:40:23 +02:00
Khoa Pham 701ae968b9 Add loading indicator 2016-10-17 10:30:20 +02:00
Khoa Pham 01d697f1f5 Point dependencies to master 2016-10-17 10:30:09 +02:00
Christoffer Winterkvist f0589a307c Disable emails on travis 2016-10-13 09:46:20 +02:00
Christoffer Winterkvist 23b49e9535 Carthage update 2016-10-13 09:46:15 +02:00
Khoa Pham 66f6d69121 Merge pull request #83 from hyperoslo/fix/loading_indicator
Add loading indicator
2016-09-30 09:03:54 +02:00
Khoa Pham 7bb0628b42 Show loading indicator when loading images 2016-09-29 12:13:04 +02:00
Khoa Pham 5b439af899 Add loading indicator 2016-09-29 11:55:28 +02:00
Khoa Pham c4f2df441f Allow arbitrary requests 2016-09-29 11:44:53 +02:00
Ramon Gilabert b1c7001b3b Removes a Travis line 2016-09-29 10:43:01 +02:00
Ramon Gilabert d70305993a Adds the new Travis 2016-09-29 10:36:06 +02:00
Ramon Gilabert a6119a3cc0 Updates the demo 2016-09-28 16:33:28 +02:00
Ramon Gilabert d1b82ee0d6 Adds the Carthage migration 2016-09-28 16:15:36 +02:00
Vadym Markov 0495a8c547 Merge pull request #80 from hyperoslo/fix/video
Video support
2016-08-08 15:31:42 +02:00
Khoa Pham b3abbd1f7a Update playButton 2016-08-07 16:52:52 +02:00
Khoa Pham 7edaaa9e69 Show and hide play button 2016-08-07 16:43:41 +02:00
Khoa Pham e6b3e5a23b Check for videoURL 2016-08-07 16:35:22 +02:00
Khoa Pham a0d45b7faf Handle video url 2016-08-07 16:30:47 +02:00
Khoa Pham ec74f08998 pod install 2016-08-07 16:30:47 +02:00
Christoffer Winterkvist 87949871e1 Merge pull request #78 from hyperoslo/fix/strong-reference
Fix strong reference
2016-06-06 13:01:55 +02:00
Christoffer Winterkvist 597181b672 Back to let 2016-06-06 12:48:26 +02:00
Christoffer Winterkvist c6795ad84d Fix lint warnings 2016-06-06 12:42:51 +02:00
Christoffer Winterkvist ddc67ff70b Make LightboxController weak 2016-06-06 12:42:45 +02:00
Christoffer Winterkvist ee9fc3dac9 Pod update 2016-06-06 12:42:35 +02:00
Christoffer Winterkvist e46ac10e84 Add .swiftlint.yml 2016-06-06 12:42:26 +02:00
Christoffer Winterkvist da39d8a72e Merge pull request #76 from hyperoslo/fix/public
Use public private(set)
2016-04-22 10:04:40 +02:00
Khoa Pham 222414ecaf Use public private(set) 2016-04-21 22:37:53 +02:00
Vadym Markov 5af42a50ad Merge pull request #75 from hyperoslo/fix/delete_animation
Adjust to make removal anomation more smooth
2016-04-15 14:52:54 +02:00
Vadym Markov 84db79b258 Merge pull request #74 from hyperoslo/improve/expand_animation
Add animation when changing alpha
2016-04-15 14:52:21 +02:00
Khoa Pham 9328d6af4e Adjust to make removal anomation more smooth 2016-04-14 09:19:42 +02:00
Khoa Pham 513d988939 Use trailing closure 2016-04-14 08:42:04 +02:00
Christoffer Winterkvist 35997d1e33 Merge pull request #72 from aashishdhawan/refactor/private-var
Making var private
2016-04-13 23:09:41 +02:00
Khoa Pham 4cef861fe9 Add animation when changing alpha 2016-04-13 16:41:33 +02:00
Christoffer Winterkvist 981fe7a222 Update travis.yml 2016-04-03 19:08:48 +02:00
Ramon Gilabert 1499bf5ecf Merge pull request #73 from hyperoslo/improve/swift-2.2
Update to Swift 2.2 syntax
2016-03-29 09:28:31 +02:00
Khoa Pham b8eacf9682 Use #selector and new range constructor 2016-03-29 09:25:16 +02:00
Aashish Dhawan 6a36b73105 Making var private 2016-02-22 23:10:49 +05:30
Vadym Markov 7f71186b9f Merge pull request #71 from hyperoslo/fix/crash
Fix crash when compiling in release mode
2016-02-22 09:37:26 +01:00
Christoffer Winterkvist 94c0969f6a Fix crash when compiling in release mode 2016-02-22 09:22:17 +01:00
Ramon Gilabert 92768bec5c Merge pull request #68 from hyperoslo/fix/presented
Fix presented property
2016-02-11 14:10:52 +01:00
Vadym Markov a4e4f1363f Fix status bar 2016-02-11 14:08:20 +01:00
Vadym Markov 2050f6d220 Configure layout on view did appear 2016-02-11 14:05:32 +01:00
Christoffer Winterkvist c0b5dc713f Merge pull request #67 from hyperoslo/fix/configure-pages
Fix a crash with configure pages in the init
2016-02-11 13:18:52 +01:00
Vadym Markov d805d1ff99 Change initial vars to let 2016-02-11 13:10:52 +01:00
Vadym Markov 2752b4c213 Move configuration to viewDidLoad 2016-02-11 11:58:01 +01:00
Vadym Markov f625c8dcf5 Change back to class 2016-02-11 11:57:47 +01:00
Vadym Markov 67d3ad03d4 Pod update 2016-02-11 11:57:27 +01:00
Ramon Gilabert 67d52df14d Merge pull request #66 from hyperoslo/fix/struct-lightbox-image
Lightbox image is a struct now
2016-02-10 15:21:26 +01:00
Vadym Markov a6d21f4488 Lightbox image is a struct now 2016-02-10 15:20:12 +01:00
Ramon Gilabert 7f0a6198f7 Merge pull request #65 from hyperoslo/fix/dynamic-background-for-remote-images
Fix dynamic background for remote images
2016-02-10 09:15:33 +01:00
Christoffer Winterkvist b1e2191471 Refactor to use guard 2016-02-10 08:59:57 +01:00
Christoffer Winterkvist 289954e998 Update travis.yml 2016-02-10 08:52:45 +01:00
Christoffer Winterkvist 012ac4f7a0 Pass remote image back in closure 2016-02-10 08:49:12 +01:00
Christoffer Winterkvist 3a2f9293a9 Make LightboxController conform to PageViewDelegate 2016-02-10 08:48:59 +01:00
Christoffer Winterkvist 36ef02a69a Add remoteImageDidLoad on PageViewDelegate 2016-02-10 08:48:37 +01:00
Christoffer Winterkvist 737ccdc826 Use imageView.image to get the image on load 2016-02-10 08:48:24 +01:00
Christoffer Winterkvist b37a1267d4 Refactor loading dynamic background into its own method 2016-02-10 08:48:09 +01:00
Christoffer Winterkvist de3405b655 Add remote image 2016-02-10 08:47:29 +01:00
Christoffer Winterkvist a52c22c4fd Allow loading remote images in demo 2016-02-10 08:47:25 +01:00
Ramon Gilabert 236b3fb8ea Merge pull request #64 from hyperoslo/feature/configuration
Feature: configuration
2016-02-01 16:44:15 +01:00
Vadym Markov 97de34d528 Make delete button hidden by default 2016-02-01 16:42:46 +01:00
Vadym Markov 2e8b8d83b3 Remove gradient if text is empty 2016-02-01 16:38:59 +01:00
Vadym Markov 44dde5db10 Use LightboxConfig everywhere 2016-02-01 16:25:16 +01:00
Vadym Markov 3d783a7cd1 Remove gradient view functions from public API 2016-02-01 16:01:02 +01:00
Vadym Markov fd98192516 Non publis transition 2016-02-01 15:58:20 +01:00
Vadym Markov 15287809aa Back config 2016-02-01 15:57:20 +01:00
Ramon Gilabert 976df91288 Merge pull request #63 from hyperoslo/feature/empty-init
Feature: set images
2016-02-01 15:40:42 +01:00
Vadym Markov 28c8d37588 Add image configuration method 2016-02-01 14:14:41 +01:00
Vadym Markov b15fc10a53 Add a setter for images 2016-02-01 14:03:03 +01:00
Christoffer Winterkvist a64d12bfcd Merge pull request #62 from hyperoslo/rfactor/config
Remove config in favour of public views.
2016-02-01 13:04:50 +01:00
Vadym Markov 74a000d632 Fix demo 2016-02-01 12:51:03 +01:00
Vadym Markov 947c49008a Rename to LightboxImageLoader 2016-02-01 12:49:01 +01:00
Vadym Markov 764f2e3bd4 Set public when it's needed 2016-02-01 12:48:25 +01:00
Vadym Markov 07231ff480 Remove model 2016-02-01 12:38:44 +01:00
Vadym Markov 70167b93c2 Move info label out of config 2016-02-01 12:31:31 +01:00
Vadym Markov 133ca2db71 Move delete button from config 2016-02-01 12:27:14 +01:00
Vadym Markov d68fa03a90 Move page indicator config 2016-02-01 12:22:01 +01:00
Vadym Markov c144d329e3 Move close button 2016-02-01 12:17:09 +01:00
Vadym Markov 29cd3b8156 Remove zoom scale 2016-02-01 09:45:44 +01:00
Vadym Markov 92ae29af6b Simplify config 2016-02-01 09:43:45 +01:00
Ramon Gilabert de0aa6399a Merge pull request #61 from hyperoslo/refactor/lightbox-image
Refactor Lightbox image
2016-01-31 19:12:23 +01:00
Christoffer Winterkvist 4bfdc39619 Make properties public 2016-01-31 19:06:04 +01:00
Christoffer Winterkvist 5ecb642592 Configure Travis 2016-01-31 19:05:57 +01:00
Ramon Gilabert 217977b4d0 Merge pull request #60 from hyperoslo/fix/dimiss-delegate
Call dismissalDelegate in finishInteractiveTransition
2016-01-31 15:47:05 +01:00
Christoffer Winterkvist e9f1178a41 Call dismissalDelegate in finishInteractiveTransition 2016-01-31 15:45:35 +01:00
Vadym Markov 30c9097671 Merge pull request #59 from hyperoslo/fix/typo-in-delegate-method
Fix typo in delegate method
2016-01-31 15:15:16 +01:00
Christoffer Winterkvist f22fa5fd12 Fix typo in delegate method 2016-01-31 15:14:00 +01:00
Christoffer Winterkvist d98e49b619 Merge pull request #47 from hyperoslo/new-implementation
New implementation request
2016-01-31 14:53:42 +01:00
Vadym Markov aa23e5eae5 Merge pull request #58 from hyperoslo/improve/rotation
Improve rotation
2016-01-31 14:45:21 +01:00
Christoffer Winterkvist f1797e4aa0 Use animateAlongsideTransition when rotating 2016-01-31 14:36:23 +01:00
Christoffer Winterkvist 3e04ad1ef1 Add autoresizingMask to demo view controller 2016-01-31 14:36:05 +01:00
Vadym Markov 0d4bb14d7e Merge pull request #56 from hyperoslo/feature/dynamic-background
Feature dynamic background
2016-01-31 14:09:40 +01:00
Christoffer Winterkvist db24073a03 Set dynamicBackground to true in demo 2016-01-31 14:00:52 +01:00
Christoffer Winterkvist 9c8f008c9a Change backgroundView image when currentPage changes 2016-01-31 14:00:38 +01:00
Christoffer Winterkvist 4a4d40194f Add dynamicBackground property setter 2016-01-31 14:00:24 +01:00
Christoffer Winterkvist e069779449 Add backgroundView 2016-01-31 14:00:11 +01:00
Christoffer Winterkvist f6bad9afe7 Add effectView 2016-01-31 14:00:05 +01:00
Christoffer Winterkvist 327f48b380 Merge pull request #54 from hyperoslo/fix/correct-accorting-to-comments
Minor fixes
2016-01-30 09:45:05 +01:00
Vadym Markov 4d3407f366 Fix alpha 2016-01-30 08:38:38 +01:00
Vadym Markov e7c511644f Use forEach 2016-01-30 08:38:25 +01:00
Vadym Markov b0f99a8529 Use Sugar 2016-01-30 08:38:07 +01:00
Vadym Markov 7e9a7aae75 Unowned self 2016-01-30 08:18:37 +01:00
Vadym Markov b8682ba8ff Merge pull request #53 from hyperoslo/improve/goto-page-in-initialiser
Add startIndex to init method
2016-01-30 08:13:48 +01:00
Christoffer Winterkvist 3d3f7c36c2 Add startIndex to init method 2016-01-29 22:00:12 +01:00
Christoffer Winterkvist c8b046d3c1 Merge pull request #52 from hyperoslo/feature/text-description
Text description feature
2016-01-29 21:36:59 +01:00
Vadym Markov 151aa54e41 Fix text update 2016-01-29 20:47:07 +01:00
Vadym Markov 7fa25f1b8a Update demo 2016-01-29 20:46:57 +01:00
Vadym Markov 57874700bc Implement lightbox image view model 2016-01-29 20:42:42 +01:00
Vadym Markov 0abd6b7eee Add functionality to hide overlay on tap 2016-01-29 20:24:06 +01:00
Vadym Markov 6a06b0f504 Hide delete button on expand 2016-01-29 20:10:39 +01:00
Vadym Markov cbbb2b1553 Fix text height 2016-01-29 20:05:49 +01:00
Vadym Markov f806688547 Update info label logic 2016-01-29 19:59:07 +01:00
Vadym Markov ba60f3eaf3 Fix gradient colors 2016-01-29 12:58:50 +01:00
Vadym Markov 6065273c22 Refactor gradient layers 2016-01-29 12:02:21 +01:00
Vadym Markov 50e1ed3b3a Fix delegates 2016-01-29 11:38:25 +01:00
Vadym Markov bf7dbe02b5 Handle footer view delegate 2016-01-29 11:23:54 +01:00
Vadym Markov fbaa24860a Add footer view delegate 2016-01-29 11:19:52 +01:00
Vadym Markov c7d52ad61f Add info label delegate 2016-01-29 11:16:11 +01:00
Vadym Markov 6ef8b11817 Refactor getters and setters 2016-01-29 10:48:15 +01:00
Vadym Markov 46018422a4 Refactor layout code 2016-01-29 10:46:12 +01:00
Vadym Markov 8f750a4501 Fix transition 2016-01-29 09:43:15 +01:00
Vadym Markov 996b519a27 Layout configurable 2016-01-29 09:42:04 +01:00
Vadym Markov f0ef356066 Setup footer view layout 2016-01-29 09:37:12 +01:00
Vadym Markov 9990486cf9 Move buttons to header view 2016-01-29 09:28:21 +01:00
Vadym Markov 73c34d36d7 Use footer view 2016-01-29 09:10:29 +01:00
Vadym Markov 6e430013ee Refactor code to use LightboxModel 2016-01-28 23:07:38 +01:00
Vadym Markov f3e7c36599 Fix info label 2016-01-28 22:27:49 +01:00
Vadym Markov bcdaf4c013 Add read more color to the config 2016-01-28 21:12:04 +01:00
Vadym Markov 27eb4f08cf Move views to a folder 2016-01-28 21:06:10 +01:00
Vadym Markov 20dc66f5a8 Update podspec 2016-01-28 21:05:55 +01:00
Vadym Markov 247fbcbd37 Add carthage folder to .gitignore 2016-01-28 21:05:37 +01:00
Vadym Markov 2abe24b17b Add carthage dependencies 2016-01-28 21:04:42 +01:00
Vadym Markov 138a9de748 Add info label configuration 2016-01-28 20:51:18 +01:00
Vadym Markov 5f1bc2a3ef Add guards 2016-01-28 20:42:40 +01:00
Vadym Markov 7e160a2382 Add ellipsis to config 2016-01-28 20:41:06 +01:00
Vadym Markov c24e4b3dbe Implement info label 2016-01-28 20:40:41 +01:00
Ramon Gilabert 4b699d70f5 Merge pull request #51 from hyperoslo/feature/double-tap-zoom
Zoom on double tap
2016-01-27 15:07:38 +01:00
Vadym Markov 02376b6313 Fix content size 2016-01-27 15:06:01 +01:00
Vadym Markov 1c8dddfa65 Handle remote images 2016-01-27 14:50:43 +01:00
Vadym Markov 6f098603fe Implement animations to show or hide controls 2016-01-27 14:44:34 +01:00
Vadym Markov 7a190be28d Implement page view delegate 2016-01-27 14:31:23 +01:00
Vadym Markov 0f2ea3673a Add page view delegate 2016-01-27 14:26:15 +01:00
Vadym Markov 2b0f12f581 Refactor code 2016-01-27 14:23:28 +01:00
Vadym Markov 3312be7a70 Add double tap recognizer 2016-01-27 14:19:09 +01:00
Ramon Gilabert 49b370f4a5 Merge pull request #50 from hyperoslo/improve/dismissal
Use velocity when calculating animation time
2016-01-27 13:18:55 +01:00
Christoffer Winterkvist 68d5cff2b4 Use velocity when calculating animation time 2016-01-27 13:13:40 +01:00
Christoffer Winterkvist 7b124968bd Merge pull request #49 from hyperoslo/feature/spacing
Spacing between pages
2016-01-27 12:57:43 +01:00
Vadym Markov f18a0d87e2 Add screen bounds var 2016-01-27 12:46:25 +01:00
Vadym Markov 2c94be7958 Use spacing 2016-01-27 12:44:13 +01:00
Christoffer Winterkvist 4aec366007 Merge pull request #48 from hyperoslo/feature/rotation
Rotation feature
2016-01-27 10:09:43 +01:00
Vadym Markov 268ba7a845 Fix framework project 2016-01-27 09:20:55 +01:00
Vadym Markov 0f1e5bed8a Refactor...refactor...refactor 2016-01-27 09:18:14 +01:00
Vadym Markov 9901ef2031 Implement delete button functionality 2016-01-27 00:00:37 +01:00
Vadym Markov 9b26d1ae88 Refactor code again 2016-01-26 22:33:06 +01:00
Vadym Markov 8505cdd8dc Set frames 2016-01-26 21:58:23 +01:00
Vadym Markov f7c8801958 Add URL init 2016-01-26 21:10:25 +01:00
Vadym Markov 18fa934091 Fix transition 2016-01-26 20:50:24 +01:00
Vadym Markov d2fcfe83e9 Add buttons and page fields 2016-01-26 20:50:19 +01:00
Vadym Markov 3d34271eca Use old config 2016-01-26 20:50:02 +01:00
Vadym Markov 1aff585870 Add marks 2016-01-26 16:38:36 +01:00
Vadym Markov c2ac20cac5 Remove breaks from switch 2016-01-26 16:36:26 +01:00
Vadym Markov 7e1ea31e87 Refactor namings 2016-01-26 16:35:53 +01:00
Vadym Markov 2c24e1e9e0 Remove print 2016-01-25 14:12:04 +01:00
Vadym Markov 020df1ef9c Rename classes 2016-01-25 14:11:45 +01:00
Vadym Markov ba5edcf2c0 Set page views frame 2016-01-25 13:52:25 +01:00
Vadym Markov f6fb1bdc44 Handle rotation in controller 2016-01-25 13:52:12 +01:00
Vadym Markov b9fbaa95df Pod update 2016-01-25 13:51:46 +01:00
Vadym Markov 8bf2ea3a3c Support multiple rotations in Demo project 2016-01-25 13:51:33 +01:00
Ramon Gilabert 9f31ca056a Removes the old demo 2016-01-12 13:43:07 +01:00
Ramon Gilabert bda3e3b87f Adds some more transition code 2016-01-12 13:36:27 +01:00
Ramon Gilabert 9607b24c34 Hides the buttons now 2016-01-12 13:02:53 +01:00
Ramon Gilabert c623ba869d Improves the transition 2016-01-12 11:37:15 +01:00
Ramon Gilabert b2e9da3dbd Fixes the transition 2016-01-12 11:33:24 +01:00
Ramon Gilabert f60deafe0e Adds both ways 2016-01-12 10:37:58 +01:00
Ramon Gilabert 87cbe6b48c Reindentation 2016-01-12 10:29:53 +01:00
Ramon Gilabert 0e7189ae17 Adds some code 2016-01-12 10:02:01 +01:00
Ramon Gilabert f3895b8eca Adds some methods 2016-01-12 09:49:37 +01:00
Ramon Gilabert 18484ac111 Adds some more transition configuration 2016-01-12 09:37:28 +01:00
Ramon Gilabert 11bd59c5ea Adds the method 2016-01-11 15:45:39 +01:00
Ramon Gilabert bc9689125b Adds the gesture recognizer 2016-01-11 15:30:14 +01:00
Ramon Gilabert 495fc0aab4 Adds the different mandatory methods 2016-01-11 15:26:48 +01:00
Ramon Gilabert c6044cecfe Done the zooming 2016-01-11 14:48:40 +01:00
Ramon Gilabert 940b44f14f Removes the controller idea 2016-01-11 14:45:38 +01:00
Ramon Gilabert 75ad50d74a Adds some information 2016-01-11 14:43:34 +01:00
Ramon Gilabert 8eb367b662 Adds the animation for the slideshow 2016-01-11 13:34:17 +01:00
Ramon Gilabert b7a89b80f4 Adds the Lightbox configuration 2016-01-11 13:24:13 +01:00
Ramon Gilabert 27d58fdced Adds the LightboxTransition 2016-01-11 13:22:32 +01:00
Ramon Gilabert 647ab2f558 Adds all the images right away 2016-01-11 12:22:23 +01:00
Ramon Gilabert 9fd3421998 Adds some configuration for the scrollView 2016-01-11 11:28:30 +01:00
Ramon Gilabert 23c1e8dadf Adds some configuration 2016-01-11 11:21:51 +01:00
Ramon Gilabert 1f1209983f Adds image controllers 2016-01-11 11:08:48 +01:00
Ramon Gilabert 6946a9941e Adds information 2016-01-11 11:01:07 +01:00
Ramon Gilabert fac4325d51 Adds the code to add the images 2016-01-11 10:55:01 +01:00
Ramon Gilabert 8a2f229c53 Adds more information 2016-01-11 10:48:00 +01:00
Ramon Gilabert 8edf8a70fa Adds the first LightboxController class 2016-01-11 10:42:33 +01:00
Ramon Gilabert d181b28e91 Deletes all the files 2016-01-11 10:41:54 +01:00
Ramon Gilabert 270f4e887f Adds the button 2016-01-11 10:35:30 +01:00
Ramon Gilabert 49766f0833 Merge remote-tracking branch 'origin/master' into new-implementation 2016-01-11 10:18:30 +01:00
Ramon Gilabert 56664f0b58 Adds the podfile 2016-01-11 09:53:07 +01:00
Ramon Gilabert a259b35826 Adds the files for the example 2016-01-11 09:50:07 +01:00
55 changed files with 2201 additions and 1641 deletions
+3
View File
@@ -28,3 +28,6 @@ DerivedData
# CocoaPods
Pods
# Carthage
Carthage
+1
View File
@@ -0,0 +1 @@
3.0
+44
View File
@@ -0,0 +1,44 @@
opt_in_rules: # some rules are only opt-in
- empty_count
# Find all the available rules by running:
# swiftlint rules
included: # paths to include during linting. `--path` is ignored if present.
- Source
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Carthage
- Pods
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
force_cast: warning # implicitly
force_try:
severity: warning # explicitly
# rules that have both warning and error levels, can set just the warning level
# implicitly
line_length: 200
# they can set both implicitly with an array
type_body_length:
- 300 # warning
- 400 # error
# or they can set both explicitly
file_length:
warning: 500
error: 1200
# naming rules can set warnings/errors for min_length and max_length
# additionally they can set excluded names
type_name:
min_length: 3 # only warning
max_length: # warning and error
warning: 40
error: 50
excluded: iPhone # excluded via string
variable_name:
min_length: # only min_length
error: 2 # only error
excluded: # excluded via string array
- x
- y
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle)
+10 -9
View File
@@ -1,12 +1,13 @@
language: objective-c
cache: cocoapods
before_install: gem install cocoapods obcd slather -N
osx_image: xcode8.3
language: swift
# Use when you don't have third party dependencies
script: xctool -project Pod/Pod.xcodeproj -scheme Tests -sdk iphonesimulator build test GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES clean test
before_install:
- brew update
- if brew outdated | grep -qx carthage; then brew upgrade carthage; fi
- travis_wait 35 carthage bootstrap --platform iOS
# Use when you have third party dependencies (CocoaPods generates a workspace)
# podfile: Pod/Podfile
# script: xctool -workspace Pod/Pod.xcworkspace -scheme Tests -sdk iphonesimulator build test GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES clean test
script:
- xcodebuild clean build -project Lightbox.xcodeproj -scheme "Lightbox-iOS" -sdk iphonesimulator
after_success: slather
notifications:
email: false
+1
View File
@@ -0,0 +1 @@
github "hyperoslo/Hue" ~> 2.0
+1
View File
@@ -0,0 +1 @@
github "hyperoslo/Hue" "f82ffc7dd55d093d3acc6ce5b3d36ca259091fdd"
@@ -1,367 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
0C9AD201C04B66C0716FF73F /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8728C35FD683AF84D7CC1A5D /* Pods.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
298CC3D01B5685B300BA502F /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 298CC3CF1B5685B300BA502F /* MainViewController.swift */; };
D5C0BDFB1B42CCBC009E6446 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5C0BDFA1B42CCBC009E6446 /* AppDelegate.swift */; };
D5C0BE021B42CCBC009E6446 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D5C0BE011B42CCBC009E6446 /* Images.xcassets */; };
D5C0BE051B42CCBC009E6446 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = D5C0BE031B42CCBC009E6446 /* LaunchScreen.xib */; };
D5C0BE1B1B42CF62009E6446 /* Podfile in Resources */ = {isa = PBXBuildFile; fileRef = D5C0BE1A1B42CF62009E6446 /* Podfile */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
23BFEEC636035C79B9D935A8 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = "<group>"; };
298CC3CF1B5685B300BA502F /* MainViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
76BF2975E45497D931B2B9C8 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = "<group>"; };
8728C35FD683AF84D7CC1A5D /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D5C0BDF51B42CCBC009E6446 /* LightboxDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LightboxDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
D5C0BDF91B42CCBC009E6446 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D5C0BDFA1B42CCBC009E6446 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
D5C0BE011B42CCBC009E6446 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
D5C0BE041B42CCBC009E6446 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = "<group>"; };
D5C0BE1A1B42CF62009E6446 /* Podfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Podfile; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
D5C0BDF21B42CCBC009E6446 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0C9AD201C04B66C0716FF73F /* Pods.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0A38C4CB9ED946C3E5379ACD /* Frameworks */ = {
isa = PBXGroup;
children = (
8728C35FD683AF84D7CC1A5D /* Pods.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
7CC838A3597315C7F8990A20 /* Pods */ = {
isa = PBXGroup;
children = (
23BFEEC636035C79B9D935A8 /* Pods.debug.xcconfig */,
76BF2975E45497D931B2B9C8 /* Pods.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
D5C0BDEC1B42CCBC009E6446 = {
isa = PBXGroup;
children = (
D5C0BE1A1B42CF62009E6446 /* Podfile */,
D5C0BDF71B42CCBC009E6446 /* LightboxDemo */,
D5C0BDF61B42CCBC009E6446 /* Products */,
7CC838A3597315C7F8990A20 /* Pods */,
0A38C4CB9ED946C3E5379ACD /* Frameworks */,
);
sourceTree = "<group>";
};
D5C0BDF61B42CCBC009E6446 /* Products */ = {
isa = PBXGroup;
children = (
D5C0BDF51B42CCBC009E6446 /* LightboxDemo.app */,
);
name = Products;
sourceTree = "<group>";
};
D5C0BDF71B42CCBC009E6446 /* LightboxDemo */ = {
isa = PBXGroup;
children = (
D5C0BDFA1B42CCBC009E6446 /* AppDelegate.swift */,
298CC3CF1B5685B300BA502F /* MainViewController.swift */,
D5C0BE011B42CCBC009E6446 /* Images.xcassets */,
D5C0BE031B42CCBC009E6446 /* LaunchScreen.xib */,
D5C0BDF81B42CCBC009E6446 /* Supporting Files */,
);
path = LightboxDemo;
sourceTree = "<group>";
};
D5C0BDF81B42CCBC009E6446 /* Supporting Files */ = {
isa = PBXGroup;
children = (
D5C0BDF91B42CCBC009E6446 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
D5C0BDF41B42CCBC009E6446 /* LightboxDemo */ = {
isa = PBXNativeTarget;
buildConfigurationList = D5C0BE141B42CCBC009E6446 /* Build configuration list for PBXNativeTarget "LightboxDemo" */;
buildPhases = (
33BD1BD41EDB7355D8EEE7B2 /* Check Pods Manifest.lock */,
D5C0BDF11B42CCBC009E6446 /* Sources */,
D5C0BDF21B42CCBC009E6446 /* Frameworks */,
D5C0BDF31B42CCBC009E6446 /* Resources */,
BC0AD25D0149B45E9C4A9A25 /* Embed Pods Frameworks */,
856840040ECE7A9C6538CCF0 /* Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = LightboxDemo;
productName = LightboxDemo;
productReference = D5C0BDF51B42CCBC009E6446 /* LightboxDemo.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
D5C0BDED1B42CCBC009E6446 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0710;
LastUpgradeCheck = 0630;
ORGANIZATIONNAME = Hyper;
TargetAttributes = {
D5C0BDF41B42CCBC009E6446 = {
CreatedOnToolsVersion = 6.3.2;
};
};
};
buildConfigurationList = D5C0BDF01B42CCBC009E6446 /* Build configuration list for PBXProject "LightboxDemo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = D5C0BDEC1B42CCBC009E6446;
productRefGroup = D5C0BDF61B42CCBC009E6446 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
D5C0BDF41B42CCBC009E6446 /* LightboxDemo */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
D5C0BDF31B42CCBC009E6446 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D5C0BE1B1B42CF62009E6446 /* Podfile in Resources */,
D5C0BE051B42CCBC009E6446 /* LaunchScreen.xib in Resources */,
D5C0BE021B42CCBC009E6446 /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
33BD1BD41EDB7355D8EEE7B2 /* Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
showEnvVarsInLog = 0;
};
856840040ECE7A9C6538CCF0 /* Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
showEnvVarsInLog = 0;
};
BC0AD25D0149B45E9C4A9A25 /* Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D5C0BDF11B42CCBC009E6446 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D5C0BDFB1B42CCBC009E6446 /* AppDelegate.swift in Sources */,
298CC3D01B5685B300BA502F /* MainViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
D5C0BE031B42CCBC009E6446 /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
D5C0BE041B42CCBC009E6446 /* Base */,
);
name = LaunchScreen.xib;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
D5C0BE121B42CCBC009E6446 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
D5C0BE131B42CCBC009E6446 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
D5C0BE151B42CCBC009E6446 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 23BFEEC636035C79B9D935A8 /* Pods.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = LightboxDemo/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Debug;
};
D5C0BE161B42CCBC009E6446 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 76BF2975E45497D931B2B9C8 /* Pods.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = LightboxDemo/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
D5C0BDF01B42CCBC009E6446 /* Build configuration list for PBXProject "LightboxDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D5C0BE121B42CCBC009E6446 /* Debug */,
D5C0BE131B42CCBC009E6446 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
D5C0BE141B42CCBC009E6446 /* Build configuration list for PBXNativeTarget "LightboxDemo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D5C0BE151B42CCBC009E6446 /* Debug */,
D5C0BE161B42CCBC009E6446 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = D5C0BDED1B42CCBC009E6446 /* Project object */;
}
@@ -1,20 +0,0 @@
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var window: UIWindow? = {
let window = UIWindow(frame: UIScreen.mainScreen().bounds)
return window
}()
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window!.rootViewController = MainViewController()
window!.backgroundColor = UIColor.whiteColor()
window!.makeKeyAndVisible()
return true
}
}
@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6214" systemVersion="14A314h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6207"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Hyper. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="LightboxDemo" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 320 KiB

@@ -1,40 +0,0 @@
import UIKit
import Lightbox
class MainViewController: UIViewController {
lazy var galleryButton: UIButton = { [unowned self] in
let button = UIButton()
button.setTitle("Show the gallery", forState: .Normal)
button.setTitleColor(UIColor(red:0.98, green:0.18, blue:0.36, alpha:1), forState: .Normal)
button.titleLabel!.font = UIFont(name: "AvenirNextCondensed-DemiBold", size: 24)
button.addTarget(self, action: "galleryButtonDidPress:", forControlEvents: .TouchUpInside)
button.frame = CGRectMake(0, 0,
UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(galleryButton)
}
// MARK: Action handlers
func galleryButtonDidPress(button: UIButton) {
let controller = LightboxController(images: ["photo1", "photo2", "photo3"])
controller.dismissalDelegate = self
presentViewController(controller, animated: true, completion: nil)
}
}
// MARK: Lightbox delegate methods
extension MainViewController : LightboxControllerDismissalDelegate {
func lightboxControllerDidDismiss(controller: LightboxController) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
}
-14
View File
@@ -1,14 +0,0 @@
PODS:
- Lightbox (0.1.0)
DEPENDENCIES:
- Lightbox (from `../../`)
EXTERNAL SOURCES:
Lightbox:
:path: ../../
SPEC CHECKSUMS:
Lightbox: 4f31e0609376469443c9b0df85efe1c737209aa5
COCOAPODS: 0.39.0.beta.4
+44
View File
@@ -0,0 +1,44 @@
opt_in_rules: # some rules are only opt-in
- empty_count
# Find all the available rules by running:
# swiftlint rules
included: # paths to include during linting. `--path` is ignored if present.
- ../../Source
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Carthage
- Pods
# configurable rules can be customized from this configuration file
# binary rules can set their severity level
force_cast: warning # implicitly
force_try:
severity: warning # explicitly
# rules that have both warning and error levels, can set just the warning level
# implicitly
line_length: 200
# they can set both implicitly with an array
type_body_length:
- 300 # warning
- 400 # error
# or they can set both explicitly
file_length:
warning: 500
error: 1200
# naming rules can set warnings/errors for min_length and max_length
# additionally they can set excluded names
type_name:
min_length: 3 # only warning
max_length: # warning and error
warning: 40
error: 50
excluded: iPhone # excluded via string
variable_name:
min_length: # only min_length
error: 2 # only error
excluded: # excluded via string array
- x
- y
- id
- URL
- GlobalAPIKey
reporter: "xcode" # reporter type (xcode, json, csv, checkstyle)
@@ -0,0 +1,382 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
29B4A42D1C43A4320060ED52 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B4A42C1C43A4320060ED52 /* AppDelegate.swift */; };
29B4A42F1C43A4320060ED52 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29B4A42E1C43A4320060ED52 /* ViewController.swift */; };
29B4A4341C43A4320060ED52 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 29B4A4331C43A4320060ED52 /* Assets.xcassets */; };
29B4A4371C43A4320060ED52 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 29B4A4351C43A4320060ED52 /* LaunchScreen.storyboard */; };
7193005DD460E198432D8F06 /* Pods_DemoLightbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0977FB7C36F459186E043753 /* Pods_DemoLightbox.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0977FB7C36F459186E043753 /* Pods_DemoLightbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DemoLightbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29B4A4291C43A4320060ED52 /* DemoLightbox.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DemoLightbox.app; sourceTree = BUILT_PRODUCTS_DIR; };
29B4A42C1C43A4320060ED52 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
29B4A42E1C43A4320060ED52 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
29B4A4331C43A4320060ED52 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
29B4A4361C43A4320060ED52 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
29B4A4381C43A4320060ED52 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5B9CE7F93A06A0459BF452D8 /* Pods-DemoLightbox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoLightbox.release.xcconfig"; path = "Pods/Target Support Files/Pods-DemoLightbox/Pods-DemoLightbox.release.xcconfig"; sourceTree = "<group>"; };
C37FDBF69CDC2A95E0E105A7 /* Pods-DemoLightbox.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-DemoLightbox.debug.xcconfig"; path = "Pods/Target Support Files/Pods-DemoLightbox/Pods-DemoLightbox.debug.xcconfig"; sourceTree = "<group>"; };
DAE713340DA5D2F2EF13EA8D /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
29B4A4261C43A4320060ED52 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7193005DD460E198432D8F06 /* Pods_DemoLightbox.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
29B4A4201C43A4320060ED52 = {
isa = PBXGroup;
children = (
29B4A42B1C43A4320060ED52 /* DemoLightbox */,
29B4A42A1C43A4320060ED52 /* Products */,
B1B2B3DADEEC7FD14D4A9FF8 /* Frameworks */,
80F119CA8153119A6934480D /* Pods */,
);
sourceTree = "<group>";
};
29B4A42A1C43A4320060ED52 /* Products */ = {
isa = PBXGroup;
children = (
29B4A4291C43A4320060ED52 /* DemoLightbox.app */,
);
name = Products;
sourceTree = "<group>";
};
29B4A42B1C43A4320060ED52 /* DemoLightbox */ = {
isa = PBXGroup;
children = (
29B4A42C1C43A4320060ED52 /* AppDelegate.swift */,
29B4A42E1C43A4320060ED52 /* ViewController.swift */,
29B4A4331C43A4320060ED52 /* Assets.xcassets */,
29B4A4351C43A4320060ED52 /* LaunchScreen.storyboard */,
29B4A4381C43A4320060ED52 /* Info.plist */,
);
path = DemoLightbox;
sourceTree = "<group>";
};
80F119CA8153119A6934480D /* Pods */ = {
isa = PBXGroup;
children = (
C37FDBF69CDC2A95E0E105A7 /* Pods-DemoLightbox.debug.xcconfig */,
5B9CE7F93A06A0459BF452D8 /* Pods-DemoLightbox.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
B1B2B3DADEEC7FD14D4A9FF8 /* Frameworks */ = {
isa = PBXGroup;
children = (
DAE713340DA5D2F2EF13EA8D /* Pods.framework */,
0977FB7C36F459186E043753 /* Pods_DemoLightbox.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
29B4A4281C43A4320060ED52 /* DemoLightbox */ = {
isa = PBXNativeTarget;
buildConfigurationList = 29B4A43B1C43A4320060ED52 /* Build configuration list for PBXNativeTarget "DemoLightbox" */;
buildPhases = (
2CF277B8821F7CE6E2730C9C /* [CP] Check Pods Manifest.lock */,
29B4A4251C43A4320060ED52 /* Sources */,
29B4A4261C43A4320060ED52 /* Frameworks */,
29B4A4271C43A4320060ED52 /* Resources */,
831C9CD301B03A92F6320AEE /* [CP] Embed Pods Frameworks */,
3BCDC27EE322C46C109D231B /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = DemoLightbox;
productName = DemoLightbox;
productReference = 29B4A4291C43A4320060ED52 /* DemoLightbox.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
29B4A4211C43A4320060ED52 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0720;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "Hyper Interaktiv AS";
TargetAttributes = {
29B4A4281C43A4320060ED52 = {
CreatedOnToolsVersion = 7.2;
DevelopmentTeam = LG4DBY4QF9;
LastSwiftMigration = 0800;
};
};
};
buildConfigurationList = 29B4A4241C43A4320060ED52 /* Build configuration list for PBXProject "DemoLightbox" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 29B4A4201C43A4320060ED52;
productRefGroup = 29B4A42A1C43A4320060ED52 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
29B4A4281C43A4320060ED52 /* DemoLightbox */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
29B4A4271C43A4320060ED52 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
29B4A4371C43A4320060ED52 /* LaunchScreen.storyboard in Resources */,
29B4A4341C43A4320060ED52 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
2CF277B8821F7CE6E2730C9C /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-DemoLightbox-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3BCDC27EE322C46C109D231B /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-DemoLightbox/Pods-DemoLightbox-resources.sh\"\n";
showEnvVarsInLog = 0;
};
831C9CD301B03A92F6320AEE /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-DemoLightbox/Pods-DemoLightbox-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/Hue/Hue.framework",
"${BUILT_PRODUCTS_DIR}/Lightbox/Lightbox.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Hue.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lightbox.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-DemoLightbox/Pods-DemoLightbox-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
29B4A4251C43A4320060ED52 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
29B4A42F1C43A4320060ED52 /* ViewController.swift in Sources */,
29B4A42D1C43A4320060ED52 /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
29B4A4351C43A4320060ED52 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
29B4A4361C43A4320060ED52 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
29B4A4391C43A4320060ED52 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
29B4A43A1C43A4320060ED52 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
29B4A43C1C43A4320060ED52 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = C37FDBF69CDC2A95E0E105A7 /* Pods-DemoLightbox.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = LG4DBY4QF9;
INFOPLIST_FILE = DemoLightbox/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = no.hyper.DemoLightbox;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
29B4A43D1C43A4320060ED52 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5B9CE7F93A06A0459BF452D8 /* Pods-DemoLightbox.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = LG4DBY4QF9;
INFOPLIST_FILE = DemoLightbox/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = no.hyper.DemoLightbox;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
29B4A4241C43A4320060ED52 /* Build configuration list for PBXProject "DemoLightbox" */ = {
isa = XCConfigurationList;
buildConfigurations = (
29B4A4391C43A4320060ED52 /* Debug */,
29B4A43A1C43A4320060ED52 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
29B4A43B1C43A4320060ED52 /* Build configuration list for PBXNativeTarget "DemoLightbox" */ = {
isa = XCConfigurationList;
buildConfigurations = (
29B4A43C1C43A4320060ED52 /* Debug */,
29B4A43D1C43A4320060ED52 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 29B4A4211C43A4320060ED52 /* Project object */;
}
@@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "self:LightboxDemo.xcodeproj">
location = "self:DemoLightbox.xcodeproj">
</FileRef>
</Workspace>
@@ -2,7 +2,7 @@
<Workspace
version = "1.0">
<FileRef
location = "group:LightboxDemo.xcodeproj">
location = "group:DemoLightbox.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
@@ -0,0 +1,18 @@
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var controller: UIViewController = ViewController()
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
window?.rootViewController = controller
window?.makeKeyAndVisible()
return true
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -6,8 +6,8 @@
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "photo1.jpg"
"filename" : "photo1.png",
"scale" : "2x"
},
{
"idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

@@ -6,8 +6,8 @@
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "photo2.jpg"
"filename" : "photo2.png",
"scale" : "2x"
},
{
"idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

@@ -6,8 +6,8 @@
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "photo3.jpg"
"filename" : "photo3.png",
"scale" : "2x"
},
{
"idiom" : "universal",
Binary file not shown.

After

Width:  |  Height:  |  Size: 987 KiB

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>no.hyper.$(PRODUCT_NAME:rfc1034identifier)</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -31,6 +31,16 @@
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>NSAppTransportSecurity</key>
<dict>
<!--Include to allow all connections (DANGER)-->
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict>
</plist>
@@ -0,0 +1,52 @@
import UIKit
import Lightbox
class ViewController: UIViewController {
lazy var showButton: UIButton = { [unowned self] in
let button = UIButton()
button.addTarget(self, action: #selector(showLightbox), for: .touchUpInside)
button.setTitle("Show me the lightbox", for: UIControlState())
button.setTitleColor(UIColor(red:0.47, green:0.6, blue:0.13, alpha:1), for: UIControlState())
button.titleLabel?.font = UIFont(name: "AvenirNextCondensed-DemiBold", size: 30)
button.frame = UIScreen.main.bounds
button.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin]
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
view.autoresizingMask = [.flexibleTopMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleBottomMargin]
view.backgroundColor = UIColor.white
view.addSubview(showButton)
}
// MARK: - Action methods
func showLightbox() {
let images = [
LightboxImage(imageURL: URL(string: "https://cdn.arstechnica.net/2011/10/05/iphone4s_sample_apple-4e8c706-intro.jpg")!),
LightboxImage(
image: UIImage(named: "photo1")!,
text: "Some very long lorem ipsum text. Some very long lorem ipsum text. Some very long lorem ipsum text. Some very long lorem ipsum text"
),
LightboxImage(
image: UIImage(named: "photo2")!,
text: "",
videoURL: URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
),
LightboxImage(
image: UIImage(named: "photo3")!,
text: "Some very long lorem ipsum text."
)
]
let controller = LightboxController(images: images)
controller.dynamicBackground = true
present(controller, animated: true, completion: nil)
}
}
@@ -4,3 +4,4 @@ use_frameworks!
inhibit_all_warnings!
pod 'Lightbox', path: '../../'
target 'DemoLightbox'
+19
View File
@@ -0,0 +1,19 @@
PODS:
- Hue (2.0.1)
- Lightbox (1.0.0):
- Hue (~> 2.0)
DEPENDENCIES:
- Lightbox (from `../../`)
EXTERNAL SOURCES:
Lightbox:
:path: ../../
SPEC CHECKSUMS:
Hue: 354caec055fdc9d38b5ef33ca2e7224721843baf
Lightbox: d15b5e265e505009932fa447f27b5262b8b1b604
PODFILE CHECKSUM: cd88b68c201e5c39cef62070056649eaee91c71b
COCOAPODS: 1.3.1
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

+8 -4
View File
@@ -1,7 +1,7 @@
Pod::Spec.new do |s|
s.name = "Lightbox"
s.summary = "A short description of Lightbox."
s.version = "0.1.0"
s.summary = "A a convenient and easy to use image viewer for your iOS app, packed with all the features you expect"
s.version = "1.1.0"
s.homepage = "https://github.com/hyperoslo/Lightbox"
s.license = 'MIT'
s.author = { "Hyper Interaktiv AS" => "ios@hyper.no" }
@@ -10,6 +10,10 @@ Pod::Spec.new do |s|
s.platform = :ios, '8.0'
s.requires_arc = true
s.source_files = 'Source/**/*'
# s.frameworks = 'UIKit', 'MapKit'
# s.dependency 'AFNetworking', '~> 2.3'
s.ios.resource = 'Resources/Lightbox.bundle'
s.frameworks = 'UIKit', 'AVFoundation', 'AVKit'
s.dependency 'Hue', '~> 2.0'
s.pod_target_xcconfig = { 'SWIFT_VERSION' => '3.0' }
end
+126 -21
View File
@@ -7,25 +7,39 @@
objects = {
/* Begin PBXBuildFile section */
D523B0BC1C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B51C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift */; };
D22006741DFB4D9700E92898 /* Lightbox.bundle in Resources */ = {isa = PBXBuildFile; fileRef = D22006731DFB4D9700E92898 /* Lightbox.bundle */; };
D2D71BBC1D54DA77006AB907 /* AssetManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D71BBB1D54DA77006AB907 /* AssetManager.swift */; };
D5026B3C1C5BF3FD003BC1A3 /* LightboxImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5026B3B1C5BF3FD003BC1A3 /* LightboxImage.swift */; };
D523B0BD1C43AA8B001AD1EC /* LightboxConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B61C43AA8A001AD1EC /* LightboxConfig.swift */; };
D523B0BE1C43AA8B001AD1EC /* LightboxController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B71C43AA8A001AD1EC /* LightboxController.swift */; };
D523B0BF1C43AA8B001AD1EC /* LightboxDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B81C43AA8A001AD1EC /* LightboxDataSource.swift */; };
D523B0C01C43AA8B001AD1EC /* LightboxTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0B91C43AA8A001AD1EC /* LightboxTransition.swift */; };
D523B0C11C43AA8B001AD1EC /* LightboxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0BA1C43AA8A001AD1EC /* LightboxView.swift */; };
D523B0C21C43AA8B001AD1EC /* LightboxViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D523B0BB1C43AA8A001AD1EC /* LightboxViewCell.swift */; };
D54DFCBE1C5AAAD600ADEA0E /* InfoLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54DFCBC1C5AAAD600ADEA0E /* InfoLabel.swift */; };
D54DFCBF1C5AAAD600ADEA0E /* PageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54DFCBD1C5AAAD600ADEA0E /* PageView.swift */; };
D54DFCC21C5AAAF100ADEA0E /* Hue.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D54DFCC01C5AAAF100ADEA0E /* Hue.framework */; };
D56F15C81E0AB79800F128AF /* LoadingIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56F15C71E0AB79800F128AF /* LoadingIndicator.swift */; };
D573A2F01C5B5605006053DD /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2EF1C5B5605006053DD /* HeaderView.swift */; };
D573A2F31C5B5C7B006053DD /* LayoutConfigurable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2F21C5B5C7B006053DD /* LayoutConfigurable.swift */; };
D573A2F51C5B5CA4006053DD /* LightboxTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2F41C5B5CA4006053DD /* LightboxTransition.swift */; };
D573A2F71C5B5E55006053DD /* UIView+Gradient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D573A2F61C5B5E55006053DD /* UIView+Gradient.swift */; };
D58A18CB1C5ABF8F000024BB /* FooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D58A18CA1C5ABF8F000024BB /* FooterView.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
D22006731DFB4D9700E92898 /* Lightbox.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Lightbox.bundle; sourceTree = "<group>"; };
D2D71BBB1D54DA77006AB907 /* AssetManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetManager.swift; sourceTree = "<group>"; };
D5026B3B1C5BF3FD003BC1A3 /* LightboxImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxImage.swift; sourceTree = "<group>"; };
D523B0A91C43AA2A001AD1EC /* Lightbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Lightbox.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D523B0AE1C43AA2A001AD1EC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
D523B0B51C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CenterCellCollectionViewFlowLayout.swift; sourceTree = "<group>"; };
D523B0B61C43AA8A001AD1EC /* LightboxConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxConfig.swift; sourceTree = "<group>"; };
D523B0B71C43AA8A001AD1EC /* LightboxController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxController.swift; sourceTree = "<group>"; };
D523B0B81C43AA8A001AD1EC /* LightboxDataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxDataSource.swift; sourceTree = "<group>"; };
D523B0B91C43AA8A001AD1EC /* LightboxTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxTransition.swift; sourceTree = "<group>"; };
D523B0BA1C43AA8A001AD1EC /* LightboxView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxView.swift; sourceTree = "<group>"; };
D523B0BB1C43AA8A001AD1EC /* LightboxViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxViewCell.swift; sourceTree = "<group>"; };
D54DFCBC1C5AAAD600ADEA0E /* InfoLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InfoLabel.swift; sourceTree = "<group>"; };
D54DFCBD1C5AAAD600ADEA0E /* PageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PageView.swift; sourceTree = "<group>"; };
D54DFCC01C5AAAF100ADEA0E /* Hue.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Hue.framework; path = Carthage/Build/iOS/Hue.framework; sourceTree = "<group>"; };
D56F15C71E0AB79800F128AF /* LoadingIndicator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingIndicator.swift; sourceTree = "<group>"; };
D573A2EF1C5B5605006053DD /* HeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = "<group>"; };
D573A2F21C5B5C7B006053DD /* LayoutConfigurable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutConfigurable.swift; sourceTree = "<group>"; };
D573A2F41C5B5CA4006053DD /* LightboxTransition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LightboxTransition.swift; sourceTree = "<group>"; };
D573A2F61C5B5E55006053DD /* UIView+Gradient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Gradient.swift"; sourceTree = "<group>"; };
D58A18CA1C5ABF8F000024BB /* FooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -33,15 +47,26 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
D54DFCC21C5AAAF100ADEA0E /* Hue.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
D22006721DFB4D9700E92898 /* Resources */ = {
isa = PBXGroup;
children = (
D22006731DFB4D9700E92898 /* Lightbox.bundle */,
);
path = Resources;
sourceTree = "<group>";
};
D523B09F1C43AA2A001AD1EC = {
isa = PBXGroup;
children = (
D22006721DFB4D9700E92898 /* Resources */,
D54DFCC01C5AAAF100ADEA0E /* Hue.framework */,
D523B0B41C43AA8A001AD1EC /* Source */,
D523B0AB1C43AA2A001AD1EC /* Lightbox */,
D523B0AA1C43AA2A001AD1EC /* Products */,
@@ -67,17 +92,38 @@
D523B0B41C43AA8A001AD1EC /* Source */ = {
isa = PBXGroup;
children = (
D523B0B51C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift */,
D573A2F11C5B5C72006053DD /* Library */,
D54DFCBB1C5AAAD600ADEA0E /* Views */,
D523B0B61C43AA8A001AD1EC /* LightboxConfig.swift */,
D523B0B71C43AA8A001AD1EC /* LightboxController.swift */,
D523B0B81C43AA8A001AD1EC /* LightboxDataSource.swift */,
D523B0B91C43AA8A001AD1EC /* LightboxTransition.swift */,
D523B0BA1C43AA8A001AD1EC /* LightboxView.swift */,
D523B0BB1C43AA8A001AD1EC /* LightboxViewCell.swift */,
D5026B3B1C5BF3FD003BC1A3 /* LightboxImage.swift */,
D2D71BBB1D54DA77006AB907 /* AssetManager.swift */,
);
path = Source;
sourceTree = "<group>";
};
D54DFCBB1C5AAAD600ADEA0E /* Views */ = {
isa = PBXGroup;
children = (
D56F15C71E0AB79800F128AF /* LoadingIndicator.swift */,
D573A2EF1C5B5605006053DD /* HeaderView.swift */,
D58A18CA1C5ABF8F000024BB /* FooterView.swift */,
D54DFCBD1C5AAAD600ADEA0E /* PageView.swift */,
D54DFCBC1C5AAAD600ADEA0E /* InfoLabel.swift */,
);
path = Views;
sourceTree = "<group>";
};
D573A2F11C5B5C72006053DD /* Library */ = {
isa = PBXGroup;
children = (
D573A2F41C5B5CA4006053DD /* LightboxTransition.swift */,
D573A2F21C5B5C7B006053DD /* LayoutConfigurable.swift */,
D573A2F61C5B5E55006053DD /* UIView+Gradient.swift */,
);
path = Library;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
@@ -99,6 +145,8 @@
D523B0A51C43AA2A001AD1EC /* Frameworks */,
D523B0A61C43AA2A001AD1EC /* Headers */,
D523B0A71C43AA2A001AD1EC /* Resources */,
D54DFCC41C5AAAF600ADEA0E /* Copy frameworks with Carthage */,
5CF8A88D1F50B4EA00C28475 /* ShellScript */,
);
buildRules = (
);
@@ -115,11 +163,12 @@
D523B0A01C43AA2A001AD1EC /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0720;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = "Hyper Interaktiv AS";
TargetAttributes = {
D523B0A81C43AA2A001AD1EC = {
CreatedOnToolsVersion = 7.2;
LastSwiftMigration = 0800;
};
};
};
@@ -145,23 +194,60 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D22006741DFB4D9700E92898 /* Lightbox.bundle in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
5CF8A88D1F50B4EA00C28475 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "if which swiftlint >/dev/null; then\nswiftlint\nelse\necho \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi";
};
D54DFCC41C5AAAF600ADEA0E /* Copy frameworks with Carthage */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"$(SRCROOT)/Carthage/Build/iOS/Hue.framework",
);
name = "Copy frameworks with Carthage";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/usr/local/bin/carthage copy-frameworks";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
D523B0A41C43AA2A001AD1EC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D56F15C81E0AB79800F128AF /* LoadingIndicator.swift in Sources */,
D54DFCBF1C5AAAD600ADEA0E /* PageView.swift in Sources */,
D573A2F71C5B5E55006053DD /* UIView+Gradient.swift in Sources */,
D523B0BD1C43AA8B001AD1EC /* LightboxConfig.swift in Sources */,
D523B0C11C43AA8B001AD1EC /* LightboxView.swift in Sources */,
D573A2F31C5B5C7B006053DD /* LayoutConfigurable.swift in Sources */,
D5026B3C1C5BF3FD003BC1A3 /* LightboxImage.swift in Sources */,
D523B0BE1C43AA8B001AD1EC /* LightboxController.swift in Sources */,
D523B0C21C43AA8B001AD1EC /* LightboxViewCell.swift in Sources */,
D523B0BC1C43AA8A001AD1EC /* CenterCellCollectionViewFlowLayout.swift in Sources */,
D523B0C01C43AA8B001AD1EC /* LightboxTransition.swift in Sources */,
D523B0BF1C43AA8B001AD1EC /* LightboxDataSource.swift in Sources */,
D54DFCBE1C5AAAD600ADEA0E /* InfoLabel.swift in Sources */,
D58A18CB1C5ABF8F000024BB /* FooterView.swift in Sources */,
D573A2F01C5B5605006053DD /* HeaderView.swift in Sources */,
D573A2F51C5B5CA4006053DD /* LightboxTransition.swift in Sources */,
D2D71BBC1D54DA77006AB907 /* AssetManager.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -181,8 +267,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -210,6 +298,7 @@
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
@@ -229,8 +318,10 @@
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
@@ -250,6 +341,8 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
@@ -260,10 +353,15 @@
D523B0B21C43AA2A001AD1EC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = Lightbox/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@@ -271,16 +369,22 @@
PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Lightbox;
PRODUCT_NAME = Lightbox;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
D523B0B31C43AA2A001AD1EC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = Lightbox/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@@ -288,6 +392,7 @@
PRODUCT_BUNDLE_IDENTIFIER = no.hyper.Lightbox;
PRODUCT_NAME = Lightbox;
SKIP_INSTALL = YES;
SWIFT_VERSION = 3.0;
};
name = Release;
};
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0720"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -15,7 +15,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D523B0A81C43AA2A001AD1EC"
BuildableName = "Lightbox-iOS.framework"
BuildableName = "Lightbox.framework"
BlueprintName = "Lightbox-iOS"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
@@ -46,7 +46,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D523B0A81C43AA2A001AD1EC"
BuildableName = "Lightbox-iOS.framework"
BuildableName = "Lightbox.framework"
BlueprintName = "Lightbox-iOS"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
@@ -64,7 +64,7 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D523B0A81C43AA2A001AD1EC"
BuildableName = "Lightbox-iOS.framework"
BuildableName = "Lightbox.framework"
BlueprintName = "Lightbox-iOS"
ReferencedContainer = "container:Lightbox.xcodeproj">
</BuildableReference>
+170 -3
View File
@@ -1,14 +1,164 @@
# Lightbox
[![CI Status](http://img.shields.io/travis/hyperoslo/Lightbox.svg?style=flat)](https://travis-ci.org/hyperoslo/Lightbox)
[![Version](https://img.shields.io/cocoapods/v/Lightbox.svg?style=flat)](http://cocoadocs.org/docsets/Lightbox)
[![CI Status](http://img.shields.io/travis/hyperoslo/Lightbox.svg?style=flat)](https://travis-ci.org/hyperoslo/Lightbox)
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![License](https://img.shields.io/cocoapods/l/Lightbox.svg?style=flat)](http://cocoadocs.org/docsets/Lightbox)
[![Platform](https://img.shields.io/cocoapods/p/Lightbox.svg?style=flat)](http://cocoadocs.org/docsets/Lightbox)
![Swift](https://img.shields.io/badge/%20in-swift%203.0-orange.svg)
[Demo](https://appetize.io/app/wfgwc2uvg82m9pzbt17p4rrgh4?device=iphone5s&scale=75&orientation=portrait&osVersion=9.3)
<img src="https://raw.githubusercontent.com/hyperoslo/Lightbox/master/Images/Icon.png" alt="Lightbox Icon" align="right" />
**Lightbox** is a convenient and easy to use image viewer for your iOS app,
packed with all the features you expect:
- [x] Paginated image slideshow.
- [x] Video support.
- [x] Double-tap to zoom.
- [x] Image caption.
- [x] Dynamic background.
- [x] Interactive transition animations.
- [x] Powerful configuration.
- [x] Demo project.
## Table of Contents
* [Usage](#usage)
* [Controller](#controller)
* [Delegates](#delegates)
* [Image loading](#image-loading)
* [Video](#video)
* [Configuration](#configuration)
* [Installation](#installation)
* [Author](#author)
* [Contributing](#contributing)
* [License](#license)
## Usage
### Controller
To start your slideshow just instantiate `LightboxController`, set needed
delegates and present it:
```swift
<API>
// Create an array of images.
let images = [
LightboxImage(imageURL: URL(string: "https://cdn.arstechnica.net/2011/10/05/iphone4s_sample_apple-4e8c706-intro.jpg")!),
LightboxImage(
image: UIImage(named: "photo1")!,
text: "This is an example of a remote image loaded from URL"
),
LightboxImage(
image: UIImage(named: "photo2")!,
text: "",
videoURL: URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
),
LightboxImage(
image: UIImage(named: "photo3")!,
text: "This is an example of a local image."
)
]
// Create an instance of LightboxController.
let controller = LightboxController(images: images)
// Set delegates.
controller.pageDelegate = self
controller.dismissalDelegate = self
// Use dynamic background.
controller.dynamicBackground = true
// Present your controller.
present(controller, animated: true, completion: nil)
```
### Delegates
Use `LightboxControllerPageDelegate` if you want to be notified about page
navigation changes.
```swift
extension ViewController: LightboxControllerPageDelegate {
func lightboxController(_ controller: LightboxController, didMoveToPage page: Int) {
print(page)
}
}
```
Use `LightboxControllerDismissalDelegate` to be notified when controller is
about to be dismissed. Please note that `LightboxController` dismisses itself
if it was presented initially.
```swift
extension ViewController: LightboxControllerDismissalDelegate: class {
func lightboxControllerWillDismiss(_ controller: LightboxController) {
// ...
}
}
```
### Image loading
By default images are loaded using `sendAsynchronousRequest` method of
`NSURLConnection`. But it's easy to change this behavior using **Lightbox**
configuration.
```swift
LightboxConfig.loadImage = {
imageView, URL, completion in
// Custom image loading
}
```
### Video
**Lightbox** has video support out of the box. Configure video by using `videoURL`:
```swift
LightboxImage(
image: UIImage(named: "photo2")!,
text: "",
videoURL: NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
)
```
Override video handling if needed:
```swift
LightboxConfig.handleVideo = { from, videoURL in
// Custom video handling
let videoController = AVPlayerViewController()
videoController.player = AVPlayer(url: videoURL)
from.present(videoController, animated: true) {
videoController.player?.play()
}
}
```
### Configuration
Configure text, colors, fonts of UI elements by overriding the static
variables in the **Lightbox** [configuration](https://github.com/hyperoslo/Lightbox/blob/master/Source/LightboxConfig.swift) struct. As an example:
```swift
LightboxConfig.CloseButton.image = UIImage(named: ImageList.Lightbox.closeButton)
LightboxConfig.CloseButton.textAttributes = TextAttributes.Lightbox.closeButton
LightboxConfig.CloseButton.text = "Finish"
LightboxConfig.DeleteButton.image = UIImage(named: ImageList.Lightbox.deleteButton)
LightboxConfig.DeleteButton.textAttributes = TextAttributes.Lightbox.deleteButton
LightboxConfig.DeleteButton.text = "Delete"
LightboxConfig.InfoLabel.ellipsisText = "ShowMore"
```
## Installation
@@ -20,10 +170,27 @@ it, simply add the following line to your Podfile:
pod 'Lightbox'
```
In order to quickly try the demo project of a **Lightbox** just run
`pod try Lightbox` in your terminal.
**Lightbox** is also available through [Carthage](https://github.com/Carthage/Carthage).
To install just write into your Cartfile:
```ruby
github "hyperoslo/Lightbox"
```
To install **Lightbox** manually just download and drop `Sources` and
`Images` folders in your project.
## Author
Hyper Interaktiv AS, ios@hyper.no
## Contributing
We would love you to contribute to **Lightbox**, check the [CONTRIBUTING](https://github.com/hyperoslo/Lightbox/blob/master/CONTRIBUTING.md) file for more info.
## License
**Lightbox** is available under the MIT license. See the LICENSE file for more info.
**Lightbox** is available under the MIT license. See the [LICENSE](https://github.com/hyperoslo/Lightbox/blob/master/LICENSE.md) file for more info.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

+9
View File
@@ -0,0 +1,9 @@
import UIKit
class AssetManager {
static func image(_ named: String) -> UIImage? {
let bundle = Bundle(for: AssetManager.self)
return UIImage(named: "Lightbox.bundle/\(named)", in: bundle, compatibleWith: nil)
}
}
@@ -1,43 +0,0 @@
import UIKit
class CenterCellCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
if let collectionView = self.collectionView {
let collectionViewBounds = collectionView.bounds
let halfWidth = collectionViewBounds.size.width / 2
let proposedContentOffsetCenterX = proposedContentOffset.x + halfWidth
if let attributesForVisibleCells = layoutAttributesForElementsInRect(collectionViewBounds) {
var candidateAttributes : UICollectionViewLayoutAttributes?
for attributes in attributesForVisibleCells.filter({
$0.representedElementCategory == UICollectionElementCategory.Cell}) {
if let candAttrs = candidateAttributes {
let a = attributes.center.x - proposedContentOffsetCenterX
let b = candAttrs.center.x - proposedContentOffsetCenterX
if velocity.x < 0 {
continue
} else if velocity.x > 0 {
candidateAttributes = attributes
} else if fabsf(Float(a)) < fabsf(Float(b)) {
candidateAttributes = attributes
}
} else { // First time in the loop
candidateAttributes = attributes
continue
}
}
return CGPoint(
x: candidateAttributes!.center.x - halfWidth,
y: proposedContentOffset.y)
}
}
return super.targetContentOffsetForProposedContentOffset(proposedContentOffset)
}
}
+4
View File
@@ -0,0 +1,4 @@
protocol LayoutConfigurable: class {
func configureLayout()
}
+181
View File
@@ -0,0 +1,181 @@
import UIKit
class LightboxTransition: UIPercentDrivenInteractiveTransition {
lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in
let gesture = UIPanGestureRecognizer()
gesture.addTarget(self, action: #selector(handlePanGesture(_:)))
gesture.delegate = self
return gesture
}()
var interactive = false
var dismissing = false
var initialOrigin = CGPoint(x: 0, y: 0)
var scrollView: UIScrollView? {
didSet {
guard let scrollView = scrollView else { return }
scrollView.addGestureRecognizer(panGestureRecognizer)
}
}
weak var lightboxController: LightboxController?
// MARK: - Transition
func transition(_ show: Bool) {
guard let controller = lightboxController else { return }
controller.headerView.transform = show
? CGAffineTransform.identity
: CGAffineTransform(translationX: 0, y: -200)
controller.footerView.transform = show
? CGAffineTransform.identity
: CGAffineTransform(translationX: 0, y: 250)
if interactive {
controller.view.backgroundColor = UIColor.black.withAlphaComponent(show ? 1 : 0)
} else {
controller.view.alpha = show ? 1 : 0
}
}
// MARK: - Pan gesture recognizer
func handlePanGesture(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: scrollView)
let percentage = abs(translation.y) / UIScreen.main.bounds.height / 1.5
let velocity = gesture.velocity(in: scrollView)
switch gesture.state {
case .began:
interactive = true
lightboxController?.presented = false
lightboxController?.dismiss(animated: true, completion: nil)
if let origin = scrollView?.frame.origin { initialOrigin = origin }
case .changed:
update(percentage)
scrollView?.frame.origin.y = initialOrigin.y + translation.y
case .ended, .cancelled:
var time = translation.y * 3 / abs(velocity.y)
if time > 1 { time = 0.7 }
interactive = false
lightboxController?.presented = true
if percentage > 0.1 {
finish()
guard let controller = lightboxController else { return }
controller.headerView.alpha = 0
controller.footerView.alpha = 0
UIView.animate(withDuration: TimeInterval(time), delay: 0, options: [.allowUserInteraction], animations: {
self.scrollView?.frame.origin.y = translation.y * 3
controller.view.alpha = 0
controller.view.backgroundColor = UIColor.black.withAlphaComponent(0)
}, completion: { _ in })
} else {
cancel()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.035) {
UIView.animate(withDuration: 0.35, animations: {
self.scrollView?.frame.origin = self.initialOrigin
})
}
}
default: break
}
}
override func finish() {
super.finish()
guard let lightboxController = lightboxController else { return }
lightboxController.dismissalDelegate?.lightboxControllerWillDismiss(lightboxController)
}
}
// MARK: - UIViewControllerAnimatedTransitioning
extension LightboxTransition: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return 0.25
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let container = transitionContext.containerView
guard let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from),
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)
else { return }
let firstView = dismissing ? toView : fromView
let secondView = dismissing ? fromView : toView
if !dismissing { transition(false) }
container.addSubview(firstView)
container.addSubview(secondView)
toView.frame = container.bounds
let duration = transitionDuration(using: transitionContext)
UIView.animate(withDuration: duration, animations: {
self.transition(!self.dismissing)
}, completion: { _ in
transitionContext.transitionWasCancelled
? transitionContext.completeTransition(false)
: transitionContext.completeTransition(true)
})
}
}
// MARK: - UIViewControllerTransitioningDelegate
extension LightboxTransition: UIViewControllerTransitioningDelegate {
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
dismissing = true
return self
}
func animationController(forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
dismissing = false
return self
}
func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
}
// MARK: - UIGestureRecognizerDelegate
extension LightboxTransition: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
var result = false
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
let translation = panGestureRecognizer.translation(in: gestureRecognizer.view)
if fabs(translation.x) < fabs(translation.y) {
result = true
}
}
return result
}
}
+30
View File
@@ -0,0 +1,30 @@
import UIKit
extension UIView {
@discardableResult func addGradientLayer(_ colors: [UIColor]) -> CAGradientLayer {
if let gradientLayer = gradientLayer { return gradientLayer }
let gradient = CAGradientLayer()
gradient.frame = bounds
gradient.colors = colors.map { $0.cgColor }
layer.insertSublayer(gradient, at: 0)
return gradient
}
func removeGradientLayer() -> CAGradientLayer? {
gradientLayer?.removeFromSuperlayer()
return gradientLayer
}
func resizeGradientLayer() {
gradientLayer?.frame = bounds
}
fileprivate var gradientLayer: CAGradientLayer? {
return layer.sublayers?.first as? CAGradientLayer
}
}
+65 -50
View File
@@ -1,90 +1,105 @@
import UIKit
import Hue
import AVKit
import AVFoundation
class LightboxConfig {
open class LightboxConfig {
var config = Config()
public typealias LoadImageCompletion = (_ error: NSError?, _ image: UIImage?) -> Void
static let sharedInstance = LightboxConfig()
}
open static var hideStatusBar = true
public struct Config {
public var hideStatusBar = true
public var backgroundColor = UIColor.clearColor()
public var pageIndicator = PageIndicator()
public var closeButton = CloseButton()
public var deleteButton = DeleteButton()
public var zoom = Zoom()
public var remoteImages = false
public var spacing: CGFloat = 20
public typealias LoadImageCompletion = (error: NSError?) -> Void
public var loadImage: (imageView: UIImageView, URL: NSURL, completion: LoadImageCompletion?) -> Void = {
open static var loadImage: (_ imageView: UIImageView, _ URL: URL, _ completion: LoadImageCompletion?) -> Void = {
imageView, URL, completion in
let imageRequest: NSURLRequest = NSURLRequest(URL: URL)
let imageRequest: URLRequest = URLRequest(url: URL)
NSURLConnection.sendAsynchronousRequest(imageRequest,
queue: NSOperationQueue.mainQueue(),
completionHandler: { response, data, error in
if let data = data, image = UIImage(data: data) {
queue: OperationQueue.main,
completionHandler: { _, data, error in
if let data = data, let image = UIImage(data: data) {
imageView.image = image
}
completion?(error: error)
completion?(error as NSError?, imageView.image)
})
}
public init() { }
open static var handleVideo: (_ from: UIViewController, _ videoURL: URL) -> Void = { from, videoURL in
let videoController = AVPlayerViewController()
videoController.player = AVPlayer(url: videoURL)
from.present(videoController, animated: true) {
videoController.player?.play()
}
}
public struct PageIndicator {
public var enabled = true
public var textAttributes = [
NSFontAttributeName: UIFont.systemFontOfSize(18),
NSForegroundColorAttributeName: UIColor.lightGrayColor(),
public static var enabled = true
public static var separatorColor = UIColor(hex: "3D4757")
public static var textAttributes = [
NSFontAttributeName: UIFont.systemFont(ofSize: 12),
NSForegroundColorAttributeName: UIColor(hex: "899AB8"),
NSParagraphStyleAttributeName: {
var style = NSMutableParagraphStyle()
style.alignment = .Center
style.alignment = .center
return style
}()
]
}
public struct CloseButton {
public var enabled = true
public var textAttributes = [
NSFontAttributeName: UIFont.boldSystemFontOfSize(12),
NSForegroundColorAttributeName: UIColor.whiteColor(),
public static var enabled = true
public static var size: CGSize?
public static var text = NSLocalizedString("Close", comment: "")
public static var image: UIImage?
public static var textAttributes = [
NSFontAttributeName: UIFont.boldSystemFont(ofSize: 16),
NSForegroundColorAttributeName: UIColor.white,
NSParagraphStyleAttributeName: {
var style = NSMutableParagraphStyle()
style.alignment = .Center
style.alignment = .center
return style
}()
]
public var size = CGSize(width: 60, height: 25)
public var text = NSLocalizedString("Close", comment: "")
public var image: UIImage?
}
public struct DeleteButton {
public var enabled = true
public var alpha: CGFloat = 0
public var textAttributes = [
NSFontAttributeName: UIFont.boldSystemFontOfSize(12),
NSForegroundColorAttributeName: UIColor(red:0.99, green:0.26, blue:0.18, alpha:1),
public static var enabled = false
public static var size: CGSize?
public static var text = NSLocalizedString("Delete", comment: "")
public static var image: UIImage?
public static var textAttributes = [
NSFontAttributeName: UIFont.boldSystemFont(ofSize: 16),
NSForegroundColorAttributeName: UIColor(hex: "FA2F5B"),
NSParagraphStyleAttributeName: {
var style = NSMutableParagraphStyle()
style.alignment = .Center
style.alignment = .center
return style
}()
]
public var size = CGSize(width: 70, height: 25)
public var text = NSLocalizedString("Delete", comment: "")
public var image: UIImage?
}
public struct InfoLabel {
public static var enabled = true
public static var textColor = UIColor.white
public static var ellipsisText = NSLocalizedString("Show more", comment: "")
public static var ellipsisColor = UIColor(hex: "899AB9")
public static var textAttributes = [
NSFontAttributeName: UIFont.systemFont(ofSize: 12),
NSForegroundColorAttributeName: UIColor(hex: "DBDBDB")
]
}
public struct Zoom {
public var minimumScale: CGFloat = 1.0
public var maximumScale: CGFloat = 3.0
public static var minimumScale: CGFloat = 1.0
public static var maximumScale: CGFloat = 3.0
}
public struct LoadingIndicator {
public static var configure: ((UIActivityIndicatorView) -> Void)?
}
}
+320 -493
View File
@@ -1,599 +1,426 @@
import UIKit
import Hue
public protocol LightboxControllerPageDelegate: class {
func lightboxControllerDidMoveToPage(controller: LightboxController, page: Int)
func lightboxController(_ controller: LightboxController, didMoveToPage page: Int)
}
public protocol LightboxControllerDismissalDelegate: class {
func lightboxControllerDidDismiss(controller: LightboxController)
func lightboxControllerWillDismiss(_ controller: LightboxController)
}
public class LightboxController: UIViewController {
public protocol LightboxControllerTouchDelegate: class {
public weak var pageDelegate: LightboxControllerPageDelegate?
public weak var dismissalDelegate: LightboxControllerDismissalDelegate?
func lightboxController(_ controller: LightboxController, didTouch image: LightboxImage, at index: Int)
}
lazy var transitionManager: LightboxTransition = { [unowned self] in
let manager = LightboxTransition()
manager.sourceViewController = self
open class LightboxController: UIViewController {
return manager
// MARK: - Internal views
lazy var scrollView: UIScrollView = { [unowned self] in
let scrollView = UIScrollView()
scrollView.frame = self.screenBounds
scrollView.isPagingEnabled = false
scrollView.delegate = self
scrollView.isUserInteractionEnabled = true
scrollView.showsHorizontalScrollIndicator = false
scrollView.decelerationRate = UIScrollViewDecelerationRateFast
return scrollView
}()
public var images = []
public var collectionSize = CGSizeZero
var pageLabelBottom: NSLayoutConstraint?
var pageLabelAlternative: NSLayoutConstraint?
var collectionViewHeight: NSLayoutConstraint?
var collectionViewWidth: NSLayoutConstraint?
var closeButtonTop: NSLayoutConstraint?
var closeButtonRight: NSLayoutConstraint?
var physics = false
lazy var overlayTapGestureRecognizer: UITapGestureRecognizer = { [unowned self] in
let gesture = UITapGestureRecognizer()
gesture.addTarget(self, action: #selector(overlayViewDidTap(_:)))
lazy var config: Config = {
return LightboxConfig.sharedInstance.config
return gesture
}()
lazy var effectView: UIVisualEffectView = {
let effect = UIBlurEffect(style: .dark)
let view = UIVisualEffectView(effect: effect)
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return view
}()
lazy var backgroundView: UIImageView = {
let view = UIImageView()
view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
return view
}()
// MARK: - Public views
open fileprivate(set) lazy var headerView: HeaderView = { [unowned self] in
let view = HeaderView()
view.delegate = self
return view
}()
var pageLabelBottomConstant: CGFloat {
return collectionSize.width < collectionSize.height ? -20 : -2
open fileprivate(set) lazy var footerView: FooterView = { [unowned self] in
let view = FooterView()
view.delegate = self
return view
}()
open fileprivate(set) lazy var overlayView: UIView = { [unowned self] in
let view = UIView(frame: CGRect.zero)
let gradient = CAGradientLayer()
let colors = [UIColor(hex: "090909").alpha(0), UIColor(hex: "040404")]
view.addGradientLayer(colors)
view.alpha = 0
return view
}()
var screenBounds: CGRect {
return UIApplication.shared.delegate?.window??.bounds ?? .zero
}
var currentOrientation: UIDeviceOrientation?
var beforeFaceOrientation: UIDeviceOrientation?
// MARK: - Properties
var rotating = false
public private(set) var page = 0 {
open fileprivate(set) var currentPage = 0 {
didSet {
page = min(images.count - 1, max(0, page))
currentPage = min(numberOfPages - 1, max(0, currentPage))
footerView.updatePage(currentPage + 1, numberOfPages)
footerView.updateText(pageViews[currentPage].image.text)
let text = "\(page + 1)/\(images.count)"
pageLabel.attributedText = NSAttributedString(string: text,
attributes: config.pageIndicator.textAttributes)
pageLabel.sizeToFit()
if page == images.count - 1 {
if currentPage == numberOfPages - 1 {
seen = true
}
pageDelegate?.lightboxControllerDidMoveToPage(self, page: page)
pageDelegate?.lightboxController(self, didMoveToPage: currentPage)
if let image = pageViews[currentPage].imageView.image, dynamicBackground {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.125) {
self.loadDynamicBackground(image)
}
}
}
}
public private(set) var seen = false
lazy var collectionView: UICollectionView = { [unowned self] in
let collectionView = UICollectionView(frame: CGRectZero,
collectionViewLayout: self.collectionViewLayout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .blackColor()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.decelerationRate = UIScrollViewDecelerationRateFast
collectionView.registerClass(LightboxViewCell.self,
forCellWithReuseIdentifier: LightboxViewCell.reuseIdentifier)
return collectionView
}()
lazy var collectionViewLayout: UICollectionViewLayout = { [unowned self] in
let layout = CenterCellCollectionViewFlowLayout()
layout.scrollDirection = .Horizontal
layout.minimumInteritemSpacing = self.config.spacing
layout.minimumLineSpacing = self.config.spacing
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
return layout
}()
lazy var pageLabel: UILabel = { [unowned self] in
let label = UILabel(frame: CGRectZero)
label.translatesAutoresizingMaskIntoConstraints = false
label.hidden = !self.config.pageIndicator.enabled
return label
}()
lazy var closeButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: self.config.closeButton.text,
attributes: self.config.closeButton.textAttributes)
let button = UIButton(type: .System)
button.tintColor = self.config.closeButton.textAttributes[NSForegroundColorAttributeName] as? UIColor
button.translatesAutoresizingMaskIntoConstraints = false
button.setAttributedTitle(title, forState: .Normal)
button.addTarget(self, action: "closeButtonDidTouchUpInside:",
forControlEvents: .TouchUpInside)
if let image = self.config.closeButton.image {
button.setBackgroundImage(image, forState: .Normal)
}
return button
}()
lazy var deleteButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: self.config.deleteButton.text,
attributes: self.config.deleteButton.textAttributes)
let button = UIButton(type: .System)
button.tintColor = self.config.deleteButton.textAttributes[NSForegroundColorAttributeName] as? UIColor
button.translatesAutoresizingMaskIntoConstraints = false
button.setAttributedTitle(title, forState: .Normal)
button.alpha = self.config.deleteButton.alpha
button.addTarget(self, action: "deleteButtonDidPress:",
forControlEvents: .TouchUpInside)
if let image = self.config.deleteButton.image {
button.setBackgroundImage(image, forState: .Normal)
}
return button
}()
// MARK: Initializers
public required init(images: [String], config: Config? = nil,
pageDelegate: LightboxControllerPageDelegate? = nil,
dismissalDelegate: LightboxControllerDismissalDelegate? = nil) {
self.images = images
self.pageDelegate = pageDelegate
self.dismissalDelegate = dismissalDelegate
if let config = config {
LightboxConfig.sharedInstance.config = config
}
super.init(nibName: nil, bundle: nil)
open var numberOfPages: Int {
return pageViews.count
}
public required init(imagesUI: [UIImage], config: Config? = nil,
pageDelegate: LightboxControllerPageDelegate? = nil,
dismissalDelegate: LightboxControllerDismissalDelegate? = nil) {
self.images = imagesUI
self.pageDelegate = pageDelegate
self.dismissalDelegate = dismissalDelegate
if let config = config {
LightboxConfig.sharedInstance.config = config
open var dynamicBackground: Bool = false {
didSet {
if dynamicBackground == true {
effectView.frame = view.frame
backgroundView.frame = effectView.frame
view.insertSubview(effectView, at: 0)
view.insertSubview(backgroundView, at: 0)
} else {
effectView.removeFromSuperview()
backgroundView.removeFromSuperview()
}
}
}
super.init(nibName: nil, bundle: nil)
open var spacing: CGFloat = 20 {
didSet {
configureLayout()
}
}
open var images: [LightboxImage] {
get {
return pageViews.map { $0.image }
}
set(value) {
configurePages(value)
}
}
open weak var pageDelegate: LightboxControllerPageDelegate?
open weak var dismissalDelegate: LightboxControllerDismissalDelegate?
open weak var imageTouchDelegate: LightboxControllerTouchDelegate?
open internal(set) var presented = false
open fileprivate(set) var seen = false
lazy var transitionManager: LightboxTransition = LightboxTransition()
var pageViews = [PageView]()
var statusBarHidden = false
fileprivate let initialImages: [LightboxImage]
fileprivate let initialPage: Int
// MARK: - Initializers
public init(images: [LightboxImage] = [], startIndex index: Int = 0) {
self.initialImages = images
self.initialPage = index
super.init(nibName: nil, bundle: nil)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - View Lifecycle
// MARK: - View lifecycle
public override func viewDidLoad() {
open override func viewDidLoad() {
super.viewDidLoad()
collectionSize = CGSizeMake(view.frame.width, view.frame.height)
for subview in [collectionView, pageLabel, closeButton, deleteButton] {
self.view.addSubview(subview)
}
statusBarHidden = UIApplication.shared.isStatusBarHidden
view.backgroundColor = UIColor.black
transitionManager.lightboxController = self
transitionManager.scrollView = scrollView
transitioningDelegate = transitionManager
transitionManager.delegate = self
view.backgroundColor = UIColor.blackColor()
let orientationsSupported: [String] = NSBundle.mainBundle().objectForInfoDictionaryKey("UISupportedInterfaceOrientations") as! [String]
[scrollView, overlayView, headerView, footerView].forEach { view.addSubview($0) }
overlayView.addGestureRecognizer(overlayTapGestureRecognizer)
currentOrientation = UIDevice.currentDevice().orientation
beforeFaceOrientation = UIDevice.currentDevice().orientation
configurePages(initialImages)
currentPage = initialPage
if orientationsSupported.first == "UIInterfaceOrientationPortrait"
&& orientationsSupported.count == 1 {
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: "deviceDidRotate",
name: UIDeviceOrientationDidChangeNotification,
object: nil)
}
setupConstraints()
page = 0
goTo(currentPage, animated: false)
}
public override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
if config.hideStatusBar {
UIApplication.sharedApplication().setStatusBarHidden(true,
withAnimation: .Fade)
}
let orientationsSupported: [String] = NSBundle.mainBundle().objectForInfoDictionaryKey("UISupportedInterfaceOrientations") as! [String]
if orientationsSupported.first == "UIInterfaceOrientationPortrait"
&& orientationsSupported.count == 1 {
if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft
|| UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight {
deviceDidRotate()
}
open override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !presented {
presented = true
configureLayout()
}
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
open override var prefersStatusBarHidden: Bool {
return LightboxConfig.hideStatusBar
}
// MARK: - Handle rotation
// MARK: - Rotation
func deviceDidRotate() {
let orientation = UIDevice.currentDevice().orientation
let orientations: [UIDeviceOrientation] = [.FaceUp, .FaceDown]
let currentIsFace = orientations.filter({ $0 == self.currentOrientation }).first != nil
let nextIsFace = orientations.filter({ $0 == orientation }).first != nil
override open func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if nextIsFace {
beforeFaceOrientation = currentOrientation
}
currentOrientation = orientation
if (!currentIsFace && nextIsFace) ||
(currentIsFace && !nextIsFace && orientation == beforeFaceOrientation) {
return
}
rotating = true
var transform = CGAffineTransformIdentity
if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft {
transform = moveCollectionView(true)
moveViews(true)
transitionManager.panGestureRecognizer.enabled = false
} else if UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight {
transform = moveCollectionView(false)
moveViews(false)
transitionManager.panGestureRecognizer.enabled = false
} else if UIDevice.currentDevice().orientation == UIDeviceOrientation.Portrait {
for constraint in [collectionViewHeight!, collectionViewWidth!,
closeButtonTop!, closeButtonRight!,
pageLabelAlternative!, pageLabelBottom!] {
view.removeConstraint(constraint)
}
standardCollectionViewConstraints()
standardCloseButtonConstraints()
standardPageLabelConstraints()
collectionView.alpha = 0
transitionManager.panGestureRecognizer.enabled = true
}
if UIDevice.currentDevice().orientation != UIDeviceOrientation.PortraitUpsideDown {
UIView.animateWithDuration(0.1, animations: { [unowned self] in
for subview in [self.collectionView, self.closeButton, self.pageLabel] { subview.alpha = 0 }
}, completion: { finished in
for subview in [self.collectionView, self.closeButton, self.pageLabel] { subview.transform = transform }
let indexPath = NSIndexPath(forItem: self.page, inSection: 0)
self.collectionView.scrollToItemAtIndexPath(indexPath,
atScrollPosition: UICollectionViewScrollPosition(), animated: false)
UIView.animateWithDuration(0.3, animations: { [unowned self] in
for subview in [self.collectionView, self.closeButton, self.pageLabel] { subview.alpha = 1 }
self.rotating = false
})
})
}
if UIDevice.currentDevice().orientation != UIDeviceOrientation.PortraitUpsideDown {
UIView.animateWithDuration(0.3, animations: { [unowned self] in
self.collectionView.transform = transform
self.closeButton.transform = transform
self.pageLabel.transform = transform
}, completion: { _ in
let indexPath = NSIndexPath(forItem: self.page, inSection: 0)
self.collectionView.scrollToItemAtIndexPath(indexPath,
atScrollPosition: UICollectionViewScrollPosition(), animated: true)
self.rotating = false
})
}
if UIDevice.currentDevice().orientation == UIDeviceOrientation.PortraitUpsideDown {
rotating = false
}
coordinator.animate(alongsideTransition: { _ in
self.configureLayout(size)
}, completion: nil)
}
// MARK: - Autolayout
// MARK: - Configuration
func setupConstraints() {
let attributes: [NSLayoutAttribute] = [.CenterX, .CenterY]
func configurePages(_ images: [LightboxImage]) {
pageViews.forEach { $0.removeFromSuperview() }
pageViews = []
for attribute in attributes {
view.addConstraint(NSLayoutConstraint(item: collectionView, attribute: attribute,
relatedBy: .Equal, toItem: self.view, attribute: attribute, multiplier: 1, constant: 0))
for image in images {
let pageView = PageView(image: image)
pageView.pageViewDelegate = self
scrollView.addSubview(pageView)
pageViews.append(pageView)
}
standardCollectionViewConstraints()
standardPageLabelConstraints()
standardCloseButtonConstraints()
standardDeleteButtonConstraints()
view.addConstraint(NSLayoutConstraint(item: closeButton, attribute: .Width,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.closeButton.size.width))
view.addConstraint(NSLayoutConstraint(item: closeButton, attribute: .Height,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.closeButton.size.height))
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Width,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.deleteButton.size.width))
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Height,
relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,
multiplier: 1, constant: config.deleteButton.size.height))
}
// MARK: - Orientation
public override func shouldAutorotate() -> Bool {
return true
}
public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.All
}
public override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
rotating = true
collectionSize = size
collectionView.collectionViewLayout.invalidateLayout()
coordinator.animateAlongsideTransition({ _ in
self.collectionView.collectionViewLayout.invalidateLayout()
self.pageLabelBottom?.constant = self.pageLabelBottomConstant
}, completion: { _ in
let indexPath = NSIndexPath(forItem: self.page, inSection: 0)
self.view.layoutIfNeeded()
self.collectionView.scrollToItemAtIndexPath(indexPath,
atScrollPosition: .CenteredHorizontally,
animated: false)
self.rotating = false
})
configureLayout()
}
// MARK: - Pagination
public func goTo(page: Int, animated: Bool = true) {
if page >= 0 && page < images.count {
var offset = collectionView.contentOffset
offset.x = CGFloat(page) * collectionSize.width
collectionView.setContentOffset(offset,
animated: animated)
open func goTo(_ page: Int, animated: Bool = true) {
guard page >= 0 && page < numberOfPages else {
return
}
currentPage = page
var offset = scrollView.contentOffset
offset.x = CGFloat(page) * (scrollView.frame.width + spacing)
let shouldAnimated = view.window != nil ? animated : false
scrollView.setContentOffset(offset, animated: shouldAnimated)
}
public func next(animated: Bool = true) {
goTo(page + 1, animated: animated)
open func next(_ animated: Bool = true) {
goTo(currentPage + 1, animated: animated)
}
public func previous(animated: Bool = true) {
goTo(page - 1, animated: animated)
open func previous(_ animated: Bool = true) {
goTo(currentPage - 1, animated: animated)
}
// MARK: - Actions
func closeButtonDidTouchUpInside(sender: UIButton) {
dismissalDelegate?.lightboxControllerDidDismiss(self)
func overlayViewDidTap(_ tapGestureRecognizer: UITapGestureRecognizer) {
footerView.expand(false)
}
func deleteButtonDidPress(button: UIButton) {
button.enabled = false
var indexPath = NSIndexPath()
let index = page
let array = images.mutableCopy() as! NSMutableArray
// MARK: - Layout
if page < images.count - 1 {
indexPath = NSIndexPath(forRow: page + 1, inSection: 0)
} else if page == images.count - 1 && images.count != 1 {
indexPath = NSIndexPath(forRow: page - 1, inSection: 0)
} else {
if array.count != 0 {
array.removeObjectAtIndex(index)
}
images = array
dismissalDelegate?.lightboxControllerDidDismiss(self)
}
open func configureLayout(_ size: CGSize = UIApplication.shared.delegate?.window??.bounds.size ?? .zero) {
scrollView.frame.size = size
scrollView.contentSize = CGSize(
width: size.width * CGFloat(numberOfPages) + spacing * CGFloat(numberOfPages - 1),
height: size.height)
scrollView.contentOffset = CGPoint(x: CGFloat(currentPage) * (size.width + spacing), y: 0)
if images.count != 0 {
collectionView.scrollToItemAtIndexPath(indexPath, atScrollPosition: .Left, animated: true)
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(0.25 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) { [unowned self] in
array.removeObjectAtIndex(index)
self.collectionView.scrollToItemAtIndexPath(NSIndexPath(forRow: index, inSection: 0), atScrollPosition: .Left, animated: false)
self.images = array
self.page = index
self.collectionView.reloadData()
button.enabled = true
for (index, pageView) in pageViews.enumerated() {
var frame = scrollView.bounds
frame.origin.x = (frame.width + spacing) * CGFloat(index)
pageView.frame = frame
pageView.configureLayout()
if index != numberOfPages - 1 {
pageView.frame.size.width += spacing
}
}
let bounds = scrollView.bounds
let headerViewHeight = headerView.closeButton.frame.height > headerView.deleteButton.frame.height
? headerView.closeButton.frame.height
: headerView.deleteButton.frame.height
headerView.frame = CGRect(x: 0, y: 16, width: bounds.width, height: headerViewHeight)
footerView.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 70)
[headerView, footerView].forEach { ($0 as AnyObject).configureLayout() }
footerView.frame.origin.y = bounds.height - footerView.frame.height
overlayView.frame = scrollView.frame
overlayView.resizeGradientLayer()
}
fileprivate func loadDynamicBackground(_ image: UIImage) {
backgroundView.image = image
backgroundView.layer.add(CATransition(), forKey: kCATransitionFade)
}
func toggleControls(pageView: PageView?, visible: Bool, duration: TimeInterval = 0.1, delay: TimeInterval = 0) {
let alpha: CGFloat = visible ? 1.0 : 0.0
pageView?.playButton.isHidden = !visible
UIView.animate(withDuration: duration, delay: delay, options: [], animations: {
self.headerView.alpha = alpha
self.footerView.alpha = alpha
pageView?.playButton.alpha = alpha
}, completion: nil)
}
}
// MARK: - UICollectionViewDelegateFlowLayout
extension LightboxController: UICollectionViewDelegateFlowLayout {
public func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return collectionSize
}
}
// MARK: - UICollectionViewDelegate
extension LightboxController: UICollectionViewDelegate { }
// MARK: - UIScrollViewDelegate
extension LightboxController: UIScrollViewDelegate {
public func scrollViewDidScroll(scrollView: UIScrollView) {
if !rotating {
let pageWidth = collectionSize.width
let currentPage = Int(floor((collectionView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
if currentPage != page { page = currentPage }
}
}
public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
var speed: CGFloat = velocity.x < 0 ? -2 : 2
public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if let cell = collectionView.visibleCells().first as? LightboxViewCell {
cell.parentViewController = self
cell.setupTransitionManager()
if velocity.x == 0 {
speed = 0
}
let pageWidth = scrollView.bounds.width + spacing
var x = scrollView.contentOffset.x + speed * 60.0
if speed > 0 {
x = ceil(x / pageWidth) * pageWidth
} else if speed < -0 {
x = floor(x / pageWidth) * pageWidth
} else {
x = round(x / pageWidth) * pageWidth
}
targetContentOffset.pointee.x = x
currentPage = Int(x / screenBounds.width)
}
}
extension LightboxController: LightboxTransitionDelegate {
// MARK: - PageViewDelegate
func transitionDidDismissController(controller: LightboxController) {
dismissalDelegate?.lightboxControllerDidDismiss(controller)
extension LightboxController: PageViewDelegate {
func remoteImageDidLoad(_ image: UIImage?, imageView: UIImageView) {
guard let image = image, dynamicBackground else {
return
}
let imageViewFrame = imageView.convert(imageView.frame, to: view)
guard view.frame.intersects(imageViewFrame) else {
return
}
loadDynamicBackground(image)
}
func pageViewDidZoom(_ pageView: PageView) {
let duration = pageView.hasZoomed ? 0.1 : 0.5
toggleControls(pageView: pageView, visible: !pageView.hasZoomed, duration: duration, delay: 0.5)
}
func pageView(_ pageView: PageView, didTouchPlayButton videoURL: URL) {
LightboxConfig.handleVideo(self, videoURL)
}
func pageViewDidTouch(_ pageView: PageView) {
guard !pageView.hasZoomed else { return }
imageTouchDelegate?.lightboxController(self, didTouch: images[currentPage], at: currentPage)
let visible = (headerView.alpha == 1.0)
toggleControls(pageView: pageView, visible: !visible)
}
}
// MARK: Custom autolayout
// MARK: - HeaderViewDelegate
extension LightboxController {
extension LightboxController: HeaderViewDelegate {
private func moveCollectionView(left: Bool) -> CGAffineTransform {
let value: CGFloat = left ? 1.57 : -1.57
let transform = CGAffineTransformMakeRotation(value)
let size = CGSizeMake(view.frame.height, view.frame.width)
func headerView(_ headerView: HeaderView, didPressDeleteButton deleteButton: UIButton) {
deleteButton.isEnabled = false
view.removeConstraint(collectionViewHeight!)
view.removeConstraint(collectionViewWidth!)
collectionViewHeight = NSLayoutConstraint(item: collectionView, attribute: .Height,
relatedBy: .Equal, toItem: view, attribute: .Width,
multiplier: 1, constant: 0)
collectionViewWidth = NSLayoutConstraint(item: collectionView, attribute: .Width,
relatedBy: .Equal, toItem: view, attribute: .Height,
multiplier: 1, constant: 0)
view.addConstraint(collectionViewHeight!)
view.addConstraint(collectionViewWidth!)
collectionSize = size
collectionView.alpha = 0
collectionView.collectionViewLayout.invalidateLayout()
view.layoutIfNeeded()
return transform
}
private func standardPageLabelConstraints() {
pageLabelAlternative = NSLayoutConstraint(item: pageLabel, attribute: .CenterX,
relatedBy: .Equal, toItem: view, attribute: .CenterX,
multiplier: 1, constant: 0)
pageLabelBottom = NSLayoutConstraint(item: pageLabel, attribute: .Bottom,
relatedBy: .Equal, toItem: view, attribute: .Bottom,
multiplier: 1, constant: pageLabelBottomConstant)
view.addConstraint(pageLabelAlternative!)
view.addConstraint(pageLabelBottom!)
}
private func standardCollectionViewConstraints() {
collectionViewWidth = NSLayoutConstraint(item: collectionView, attribute: .Width,
relatedBy: .Equal, toItem: view, attribute: .Width,
multiplier: 1, constant: 0)
collectionViewHeight = NSLayoutConstraint(item: collectionView, attribute: .Height,
relatedBy: .Equal, toItem: view, attribute: .Height,
multiplier: 1, constant: 0)
collectionSize = CGSizeMake(view.frame.width, view.frame.height)
collectionView.reloadData()
view.addConstraint(collectionViewWidth!)
view.addConstraint(collectionViewHeight!)
}
private func standardCloseButtonConstraints() {
closeButtonTop = NSLayoutConstraint(item: closeButton, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 16)
closeButtonRight = NSLayoutConstraint(item: closeButton, attribute: .Right,
relatedBy: .Equal, toItem: view, attribute: .Right,
multiplier: 1, constant: -17)
view.addConstraint(closeButtonTop!)
view.addConstraint(closeButtonRight!)
}
private func standardDeleteButtonConstraints() {
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 16))
view.addConstraint(NSLayoutConstraint(item: deleteButton, attribute: .Left,
relatedBy: .Equal, toItem: view, attribute: .Left,
multiplier: 1, constant: 17))
}
private func moveViews(left: Bool) {
for constraint in [closeButtonTop!, closeButtonRight!,
pageLabelAlternative!, pageLabelBottom!] {
view.removeConstraint(constraint)
guard numberOfPages != 1 else {
pageViews.removeAll()
self.headerView(headerView, didPressCloseButton: headerView.closeButton)
return
}
closeButtonRight = left ?
NSLayoutConstraint(item: closeButton, attribute: .Right,
relatedBy: .Equal, toItem: view, attribute: .Right,
multiplier: 1, constant: 0) :
NSLayoutConstraint(item: closeButton, attribute: .Left,
relatedBy: .Equal, toItem: view, attribute: .Left,
multiplier: 1, constant: 0)
let prevIndex = currentPage
closeButtonTop = left
? NSLayoutConstraint(item: closeButton, attribute: .Bottom,
relatedBy: .Equal, toItem: view, attribute: .Bottom,
multiplier: 1, constant: -35)
: NSLayoutConstraint(item: closeButton, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 35)
pageLabelBottom = left
? NSLayoutConstraint(item: pageLabel, attribute: .Left,
relatedBy: .Equal, toItem: view, attribute: .Left,
multiplier: 1, constant: 20)
: NSLayoutConstraint(item: pageLabel, attribute: .Top,
relatedBy: .Equal, toItem: view, attribute: .Top,
multiplier: 1, constant: 20)
pageLabelAlternative = left
? NSLayoutConstraint(item: pageLabel, attribute: .Bottom,
relatedBy: .Equal, toItem: view, attribute: .Bottom,
multiplier: 1, constant: -20)
: NSLayoutConstraint(item: pageLabel, attribute: .Right,
relatedBy: .Equal, toItem: view, attribute: .Right,
multiplier: 1, constant: -20)
for constraint in [closeButtonTop!, closeButtonRight!,
pageLabelAlternative!, pageLabelBottom!] {
view.addConstraint(constraint)
if currentPage == numberOfPages - 1 {
previous()
} else {
next()
currentPage -= 1
}
self.pageViews.remove(at: prevIndex).removeFromSuperview()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.5) {
self.configureLayout()
self.currentPage = Int(self.scrollView.contentOffset.x / self.screenBounds.width)
deleteButton.isEnabled = true
}
}
func headerView(_ headerView: HeaderView, didPressCloseButton closeButton: UIButton) {
closeButton.isEnabled = false
presented = false
dismissalDelegate?.lightboxControllerWillDismiss(self)
dismiss(animated: true, completion: nil)
}
}
// MARK: - FooterViewDelegate
extension LightboxController: FooterViewDelegate {
public func footerView(_ footerView: FooterView, didExpand expanded: Bool) {
footerView.frame.origin.y = screenBounds.height - footerView.frame.height
UIView.animate(withDuration: 0.25, animations: {
self.overlayView.alpha = expanded ? 1.0 : 0.0
self.headerView.deleteButton.alpha = expanded ? 0.0 : 1.0
})
}
}
-41
View File
@@ -1,41 +0,0 @@
import UIKit
extension LightboxController: UICollectionViewDataSource {
public func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
public func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cellIdentifier = LightboxViewCell.reuseIdentifier
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier,
forIndexPath: indexPath) as! LightboxViewCell
let image: AnyObject = images[indexPath.row]
let config = LightboxConfig.sharedInstance.config
cell.parentViewController = self
cell.loadingIndicator.alpha = 0
cell.setupTransitionManager()
if let imageString = image as? String {
if let imageURL = NSURL(string: imageString) where config.remoteImages {
cell.loadingIndicator.alpha = 1
config.loadImage(
imageView: cell.lightboxView.imageView, URL: imageURL) { error in
if error == nil {
cell.loadingIndicator.alpha = 0
cell.lightboxView.updateViewLayout()
}
}
} else {
cell.lightboxView.imageView.image = UIImage(named: imageString)
cell.lightboxView.updateViewLayout()
}
} else if let image = image as? UIImage {
cell.lightboxView.imageView.image = image
cell.lightboxView.updateViewLayout()
}
return cell
}
}
+35
View File
@@ -0,0 +1,35 @@
import UIKit
open class LightboxImage {
open fileprivate(set) var image: UIImage?
open fileprivate(set) var imageURL: URL?
open fileprivate(set) var videoURL: URL?
open var text: String
// MARK: - Initialization
public init(image: UIImage, text: String = "", videoURL: URL? = nil) {
self.image = image
self.text = text
self.videoURL = videoURL
}
public init(imageURL: URL, text: String = "", videoURL: URL? = nil) {
self.imageURL = imageURL
self.text = text
self.videoURL = videoURL
}
open func addImageTo(_ imageView: UIImageView, completion: ((_ image: UIImage?) -> Void)? = nil) {
if let image = image {
imageView.image = image
completion?(image)
} else if let imageURL = imageURL {
LightboxConfig.loadImage(imageView, imageURL) { [weak self] _, image in
self?.image = image
completion?(image)
}
}
}
}
-254
View File
@@ -1,254 +0,0 @@
import UIKit
protocol LightboxTransitionDelegate: class {
func transitionDidDismissController(controller: LightboxController)
}
class LightboxTransition: UIPercentDrivenInteractiveTransition {
struct Timing {
static let transition: NSTimeInterval = 0.4
}
lazy var panGestureRecognizer: UIPanGestureRecognizer = { [unowned self] in
let panGestureRecognizer = UIPanGestureRecognizer()
panGestureRecognizer.addTarget(self, action: "handlePanGesture:")
panGestureRecognizer.delegate = self
return panGestureRecognizer
}()
var presentingViewController = false
var interactive = false
var animator: UIDynamicAnimator!
var attachmentBehavior: UIAttachmentBehavior!
var gravityBehaviour: UIGravityBehavior!
var snapBehavior: UISnapBehavior!
weak var sourceViewController: LightboxController!
weak var delegate: LightboxTransitionDelegate?
weak var lightboxController: LightboxController!
weak var sourceViewCell: LightboxViewCell? {
didSet {
sourceViewCell?.addGestureRecognizer(panGestureRecognizer)
}
}
func transition(controller: LightboxController, show: Bool) {
lightboxController = controller
if UIDevice.currentDevice().orientation != UIDeviceOrientation.LandscapeLeft
&& UIDevice.currentDevice().orientation != UIDeviceOrientation.LandscapeRight {
if sourceViewCell != nil {
self.sourceViewCell?.lightboxView.imageView.center = CGPointMake(
UIScreen.mainScreen().bounds.width/2, UIScreen.mainScreen().bounds.height/2)
}
controller.pageLabel.transform = show ? CGAffineTransformIdentity : CGAffineTransformMakeTranslation(0, 250)
for button in [controller.closeButton, controller.deleteButton] {
button.transform = show
? CGAffineTransformIdentity
: CGAffineTransformMakeTranslation(0, -250)
}
}
if presentingViewController {
controller.collectionView.transform = show ? CGAffineTransformIdentity : CGAffineTransformMakeScale(0.5, 0.5)
controller.view.alpha = show ? 1 : 0.01
} else if !interactive {
controller.view.alpha = show ? 1 : 0.1
} else {
controller.view.alpha = show ? 1 : 0.95
}
}
}
// MARK: Transitioning delegate
extension LightboxTransition : UIViewControllerAnimatedTransitioning {
func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return Timing.transition
}
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView()
let screens : (from: UIViewController, to: UIViewController) = (
transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!,
transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!)
let lightboxViewController = !presentingViewController
? screens.from as! LightboxController
: screens.to as! LightboxController
let viewController = !presentingViewController
? screens.to as UIViewController
: screens.from as UIViewController
for controller in [viewController, lightboxViewController] {
containerView?.addSubview(controller.view)
}
if presentingViewController {
transition(lightboxViewController, show: false)
}
UIView.animateWithDuration(Timing.transition, animations: { [unowned self] in
self.transition(lightboxViewController, show: self.presentingViewController)
}, completion: { _ in
if transitionContext.transitionWasCancelled() {
UIView.animateWithDuration(Timing.transition/3, animations: { [unowned self] in
self.sourceViewCell?.lightboxView.imageView.center = CGPointMake(
UIScreen.mainScreen().bounds.width/2, UIScreen.mainScreen().bounds.height/2)
self.transition(lightboxViewController, show: true)
}, completion: { finished in
transitionContext.completeTransition(false)
UIApplication.sharedApplication().keyWindow?.addSubview(screens.from.view)
})
} else {
if self.lightboxController.view.alpha < 0.97 && !self.presentingViewController {
UIView.animateWithDuration(0.4, animations: {
lightboxViewController.view.alpha = 0
}, completion: { _ in
transitionContext.completeTransition(true)
})
} else {
transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow?.addSubview(screens.to.view)
}
}
})
}
}
// MARK: Transition delegate
extension LightboxTransition : UIViewControllerTransitioningDelegate {
func animationControllerForPresentedController(presented: UIViewController,
presentingController presenting: UIViewController,
sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
presentingViewController = true
return self
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
presentingViewController = false
return self
}
func interactionControllerForDismissal(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
func interactionControllerForPresentation(animator: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
return interactive ? self : nil
}
}
// MARK: Interactive transition delegate
extension LightboxTransition {
func handlePanGesture(panGestureRecognizer: UIPanGestureRecognizer) {
guard let imageView = sourceViewCell?.lightboxView.imageView else { return }
let location = panGestureRecognizer.locationInView(sourceViewCell?.lightboxView)
let boxLocation = panGestureRecognizer.locationInView(imageView)
let translation = panGestureRecognizer.translationInView(sourceViewCell?.lightboxView)
let percentage = fabs(translation.y / UIScreen.mainScreen().bounds.height)
if percentage > 0.35 {
transition(lightboxController, show: false)
}
if let controller = sourceViewCell?.parentViewController where controller.physics {
if panGestureRecognizer.state == UIGestureRecognizerState.Began {
interactive = true
sourceViewController.dismissViewControllerAnimated(true, completion: nil)
animator.removeBehavior(snapBehavior)
let centerOffset = UIOffsetMake(boxLocation.x - CGRectGetMidX(imageView.bounds),
boxLocation.y - CGRectGetMidY(imageView.bounds))
attachmentBehavior = UIAttachmentBehavior(item: imageView,
offsetFromCenter: centerOffset, attachedToAnchor: location)
attachmentBehavior.frequency = 0
animator.addBehavior(attachmentBehavior)
} else if panGestureRecognizer.state == UIGestureRecognizerState.Changed {
attachmentBehavior.anchorPoint = location
updateInteractiveTransition(percentage)
} else if panGestureRecognizer.state == UIGestureRecognizerState.Ended {
interactive = false
if percentage > 0.35 {
finishInteractiveTransition()
delegate?.transitionDidDismissController(lightboxController)
} else {
cancelInteractiveTransition()
if let cell = sourceViewCell {
animator.removeBehavior(attachmentBehavior)
snapBehavior = UISnapBehavior(item: imageView,
snapToPoint: cell.lightboxView.center)
animator.addBehavior(snapBehavior)
}
}
}
} else {
if panGestureRecognizer.state == .Began {
interactive = true
sourceViewController.dismissViewControllerAnimated(true, completion: nil)
} else if panGestureRecognizer.state == .Changed {
imageView.center = CGPointMake(imageView.center.x, UIScreen.mainScreen().bounds.height/2 + translation.y)
updateInteractiveTransition(percentage)
} else {
interactive = false
if percentage > 0.35 {
finishInteractiveTransition()
delegate?.transitionDidDismissController(lightboxController)
lightboxController.collectionView.alpha = 0
} else {
cancelInteractiveTransition()
}
}
}
}
override func finishInteractiveTransition() {
super.finishInteractiveTransition()
guard let cell = sourceViewCell else { return }
let point = (cell.lightboxView.imageView.center.y - UIScreen.mainScreen().bounds.height/2) * 10
UIView.animateWithDuration(Timing.transition, animations: { [unowned self] in
self.sourceViewCell?.lightboxView.imageView.center = CGPointMake(
UIScreen.mainScreen().bounds.width/2, point)
}, completion: { _ in
guard let cell = self.sourceViewCell else { return }
if let controller = cell.parentViewController where controller.physics {
self.animator.removeBehavior(self.attachmentBehavior)
self.snapBehavior = UISnapBehavior(item: cell.lightboxView.imageView,
snapToPoint: cell.lightboxView.center)
self.animator.addBehavior(self.snapBehavior)
}
})
sourceViewController.collectionView.scrollRectToVisible(
CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height),
animated: false)
}
}
// MARK: Gesture recognizer delegate methods
extension LightboxTransition : UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer {
let translation = panGestureRecognizer.translationInView(sourceViewCell?.superview!)
if fabs(translation.x) < fabs(translation.y) {
return true
}
}
return false
}
}
-165
View File
@@ -1,165 +0,0 @@
import UIKit
public class LightboxView: UIView {
public var minimumZoomScale: CGFloat = 1
public var maximumZoomScale: CGFloat = 3
var lastZoomScale: CGFloat = -1
lazy var imageView: UIImageView = {
let imageView = UIImageView(frame: CGRectZero)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.userInteractionEnabled = true
return imageView
}()
lazy var scrollView: UIScrollView = { [unowned self] in
let scrollView = UIScrollView(frame: CGRectZero)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.multipleTouchEnabled = true
scrollView.minimumZoomScale = self.minimumZoomScale
scrollView.maximumZoomScale = self.maximumZoomScale
scrollView.delegate = self
scrollView.showsVerticalScrollIndicator = false
scrollView.showsHorizontalScrollIndicator = false
return scrollView
}()
var imageConstraintLeading: NSLayoutConstraint!
var imageConstraintTrailing: NSLayoutConstraint!
var imageConstraintTop: NSLayoutConstraint!
var imageConstraintBottom: NSLayoutConstraint!
var constraintsAdded = false
// MARK: - Initialization
public init(frame: CGRect, image: UIImage? = nil) {
super.init(frame: frame)
imageView.image = image
let config = LightboxConfig.sharedInstance.config
backgroundColor = config.backgroundColor
minimumZoomScale = config.zoom.minimumScale
maximumZoomScale = config.zoom.maximumScale
scrollView.addSubview(imageView)
addSubview(scrollView)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - View lifecycle
public override func didMoveToSuperview() {
setUpConstraints()
}
// MARK: - Public methods
public func updateViewLayout() {
if constraintsAdded {
updateImageConstraints()
updateZoom()
}
}
// MARK: - Autolayout
public func setUpConstraints() {
if !constraintsAdded {
let layoutAttributes: [NSLayoutAttribute] = [.Leading, .Trailing, .Top, .Bottom]
for layoutAttribute in layoutAttributes {
addConstraint(NSLayoutConstraint(item: self.scrollView, attribute: layoutAttribute,
relatedBy: .Equal, toItem: self, attribute: layoutAttribute,
multiplier: 1, constant: 0))
}
imageConstraintLeading = NSLayoutConstraint(item: imageView, attribute: .Leading,
relatedBy: .Equal, toItem: scrollView, attribute: .Leading,
multiplier: 1, constant: 0)
imageConstraintTrailing = NSLayoutConstraint(item: imageView, attribute: .Trailing,
relatedBy: .Equal, toItem: scrollView, attribute: .Trailing,
multiplier: 1, constant: 0)
imageConstraintTop = NSLayoutConstraint(item: imageView, attribute: .Top,
relatedBy: .Equal, toItem: scrollView, attribute: .Top,
multiplier: 1, constant: 0)
imageConstraintBottom = NSLayoutConstraint(item: imageView, attribute: .Bottom,
relatedBy: .Equal, toItem: scrollView, attribute: .Bottom,
multiplier: 1, constant: 0)
addConstraints([imageConstraintLeading, imageConstraintTrailing,
imageConstraintTop, imageConstraintBottom])
layoutIfNeeded()
scrollView.contentSize = CGSize(width: frame.size.width, height: frame.size.height)
constraintsAdded = true
}
}
public func updateImageConstraints() {
if let image = imageView.image {
// Center image
var hPadding = (bounds.size.width - scrollView.zoomScale * image.size.width) / 2
if hPadding < 0 {
hPadding = 0
}
var vPadding = (bounds.size.height - scrollView.zoomScale * image.size.height) / 2
if vPadding < 0 {
vPadding = 0
}
for constraint in [imageConstraintLeading, imageConstraintTrailing] { constraint.constant = hPadding }
for constraint in [imageConstraintTop, imageConstraintBottom] { constraint.constant = vPadding }
layoutIfNeeded()
}
}
// MARK: - Zoom
public func updateZoom() {
if let image = imageView.image {
var minimumZoom = min(
bounds.size.width / image.size.width,
bounds.size.height / image.size.height)
if minimumZoom > 1 {
minimumZoom = 1
}
scrollView.minimumZoomScale = minimumZoom
if minimumZoom == lastZoomScale {
minimumZoom += 0.000001
}
scrollView.zoomScale = minimumZoom
lastZoomScale = minimumZoom
}
}
}
// MARK: - UIScrollViewDelegate
extension LightboxView: UIScrollViewDelegate {
public func scrollViewDidZoom(scrollView: UIScrollView) {
updateImageConstraints()
}
public func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return imageView
}
}
-63
View File
@@ -1,63 +0,0 @@
import UIKit
public class LightboxViewCell: UICollectionViewCell {
public static let reuseIdentifier: String = "LightboxViewCell"
var constraintsAdded = false
weak var parentViewController: LightboxController?
public lazy var lightboxView: LightboxView = { [unowned self] in
let lightboxView = LightboxView(frame: self.bounds)
lightboxView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(lightboxView)
return lightboxView
}()
public lazy var loadingIndicator: UIActivityIndicatorView = {
let loadingIndicator = UIActivityIndicatorView(activityIndicatorStyle: .White)
loadingIndicator.startAnimating()
loadingIndicator.alpha = 0
loadingIndicator.translatesAutoresizingMaskIntoConstraints = false
return loadingIndicator
}()
public override func layoutSubviews() {
super.layoutSubviews()
if loadingIndicator.superview == nil { self.contentView.addSubview(loadingIndicator) }
setupConstraints()
lightboxView.updateViewLayout()
}
public func setupTransitionManager() {
guard let controller = parentViewController else { return }
controller.transitionManager.sourceViewCell = self
controller.transitionManager.animator = UIDynamicAnimator(referenceView: lightboxView)
}
private func setupConstraints() {
if !constraintsAdded {
let layoutAttributes: [NSLayoutAttribute] = [.Leading, .Trailing, .Top, .Bottom]
for layoutAttribute in layoutAttributes {
addConstraint(NSLayoutConstraint(item: lightboxView, attribute: layoutAttribute,
relatedBy: .Equal, toItem: contentView, attribute: layoutAttribute,
multiplier: 1, constant: 0))
}
addConstraint(NSLayoutConstraint(item: loadingIndicator, attribute: .CenterX,
relatedBy: .Equal, toItem: self.contentView, attribute: .CenterX,
multiplier: 1, constant: 0))
addConstraint(NSLayoutConstraint(item: loadingIndicator, attribute: .CenterY,
relatedBy: .Equal, toItem: self.contentView, attribute: .CenterY,
multiplier: 1, constant: 0))
constraintsAdded = true
}
}
}
+114
View File
@@ -0,0 +1,114 @@
import UIKit
public protocol FooterViewDelegate: class {
func footerView(_ footerView: FooterView, didExpand expanded: Bool)
}
open class FooterView: UIView {
open fileprivate(set) lazy var infoLabel: InfoLabel = { [unowned self] in
let label = InfoLabel(text: "")
label.isHidden = !LightboxConfig.InfoLabel.enabled
label.textColor = LightboxConfig.InfoLabel.textColor
label.isUserInteractionEnabled = true
label.delegate = self
return label
}()
open fileprivate(set) lazy var pageLabel: UILabel = { [unowned self] in
let label = UILabel(frame: CGRect.zero)
label.isHidden = !LightboxConfig.PageIndicator.enabled
label.numberOfLines = 1
return label
}()
open fileprivate(set) lazy var separatorView: UIView = { [unowned self] in
let view = UILabel(frame: CGRect.zero)
view.isHidden = !LightboxConfig.PageIndicator.enabled
view.backgroundColor = LightboxConfig.PageIndicator.separatorColor
return view
}()
let gradientColors = [UIColor(hex: "040404").alpha(0.1), UIColor(hex: "040404")]
open weak var delegate: FooterViewDelegate?
// MARK: - Initializers
public init() {
super.init(frame: CGRect.zero)
backgroundColor = UIColor.clear
_ = addGradientLayer(gradientColors)
[pageLabel, infoLabel, separatorView].forEach { addSubview($0) }
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Helpers
func expand(_ expand: Bool) {
expand ? infoLabel.expand() : infoLabel.collapse()
}
func updatePage(_ page: Int, _ numberOfPages: Int) {
let text = "\(page)/\(numberOfPages)"
pageLabel.attributedText = NSAttributedString(string: text,
attributes: LightboxConfig.PageIndicator.textAttributes)
pageLabel.sizeToFit()
}
func updateText(_ text: String) {
infoLabel.fullText = text
if text.isEmpty {
_ = removeGradientLayer()
} else if !infoLabel.expanded {
_ = addGradientLayer(gradientColors)
}
}
// MARK: - Layout
fileprivate func resetFrames() {
frame.size.height = infoLabel.frame.height + 40 + 0.5
pageLabel.frame.origin = CGPoint(
x: (frame.width - pageLabel.frame.width) / 2,
y: frame.height - pageLabel.frame.height - 2)
separatorView.frame = CGRect(x: 0, y: pageLabel.frame.minY - 2.5,
width: frame.width, height: 0.5)
infoLabel.frame.origin.y = separatorView.frame.minY - infoLabel.frame.height - 15
resizeGradientLayer()
}
}
// MARK: - LayoutConfigurable
extension FooterView: LayoutConfigurable {
public func configureLayout() {
infoLabel.frame = CGRect(x: 17, y: 0, width: frame.width - 17 * 2, height: 35)
infoLabel.configureLayout()
}
}
extension FooterView: InfoLabelDelegate {
public func infoLabel(_ infoLabel: InfoLabel, didExpand expanded: Bool) {
resetFrames()
_ = (expanded || infoLabel.fullText.isEmpty) ? removeGradientLayer() : addGradientLayer(gradientColors)
delegate?.footerView(self, didExpand: expanded)
}
}
+107
View File
@@ -0,0 +1,107 @@
import UIKit
protocol HeaderViewDelegate: class {
func headerView(_ headerView: HeaderView, didPressDeleteButton deleteButton: UIButton)
func headerView(_ headerView: HeaderView, didPressCloseButton closeButton: UIButton)
}
open class HeaderView: UIView {
var centerTextStyle: NSMutableParagraphStyle = {
var style = NSMutableParagraphStyle()
style.alignment = .center
return style
}()
open fileprivate(set) lazy var closeButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: LightboxConfig.CloseButton.text,
attributes: LightboxConfig.CloseButton.textAttributes)
let button = UIButton(type: .system)
button.setAttributedTitle(title, for: UIControlState())
if let size = LightboxConfig.CloseButton.size {
button.frame.size = size
} else {
button.sizeToFit()
}
button.addTarget(self, action: #selector(closeButtonDidPress(_:)),
for: .touchUpInside)
if let image = LightboxConfig.CloseButton.image {
button.setBackgroundImage(image, for: UIControlState())
}
button.isHidden = !LightboxConfig.CloseButton.enabled
return button
}()
open fileprivate(set) lazy var deleteButton: UIButton = { [unowned self] in
let title = NSAttributedString(
string: LightboxConfig.DeleteButton.text,
attributes: LightboxConfig.DeleteButton.textAttributes)
let button = UIButton(type: .system)
button.setAttributedTitle(title, for: .normal)
if let size = LightboxConfig.DeleteButton.size {
button.frame.size = size
} else {
button.sizeToFit()
}
button.addTarget(self, action: #selector(deleteButtonDidPress(_:)),
for: .touchUpInside)
if let image = LightboxConfig.DeleteButton.image {
button.setBackgroundImage(image, for: UIControlState())
}
button.isHidden = !LightboxConfig.DeleteButton.enabled
return button
}()
weak var delegate: HeaderViewDelegate?
// MARK: - Initializers
public init() {
super.init(frame: CGRect.zero)
backgroundColor = UIColor.clear
[closeButton, deleteButton].forEach { addSubview($0) }
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Actions
func deleteButtonDidPress(_ button: UIButton) {
delegate?.headerView(self, didPressDeleteButton: button)
}
func closeButtonDidPress(_ button: UIButton) {
delegate?.headerView(self, didPressCloseButton: button)
}
}
// MARK: - LayoutConfigurable
extension HeaderView: LayoutConfigurable {
public func configureLayout() {
closeButton.frame.origin = CGPoint(
x: bounds.width - closeButton.frame.width - 17, y: 0)
deleteButton.frame.origin = CGPoint(x: 17, y: 0)
}
}
+146
View File
@@ -0,0 +1,146 @@
import UIKit
public protocol InfoLabelDelegate: class {
func infoLabel(_ infoLabel: InfoLabel, didExpand expanded: Bool)
}
open class InfoLabel: UILabel {
lazy var tapGestureRecognizer: UITapGestureRecognizer = { [unowned self] in
let gesture = UITapGestureRecognizer()
gesture.addTarget(self, action: #selector(labelDidTap(_:)))
return gesture
}()
open var numberOfVisibleLines = 2
var ellipsis: String {
return "... \(LightboxConfig.InfoLabel.ellipsisText)"
}
open weak var delegate: InfoLabelDelegate?
fileprivate var shortText = ""
var fullText: String {
didSet {
shortText = truncatedText
updateText(fullText)
configureLayout()
}
}
var expandable: Bool {
return shortText != fullText
}
fileprivate(set) var expanded = false {
didSet {
delegate?.infoLabel(self, didExpand: expanded)
}
}
fileprivate var truncatedText: String {
var truncatedText = fullText
guard numberOfLines(fullText) > numberOfVisibleLines else {
return truncatedText
}
while numberOfLines(truncatedText) > numberOfVisibleLines * 2 {
truncatedText = String(truncatedText.characters.prefix(truncatedText.characters.count / 2))
}
truncatedText += ellipsis
let start = truncatedText.characters.index(truncatedText.endIndex, offsetBy: -(ellipsis.characters.count + 1))
let end = truncatedText.characters.index(truncatedText.endIndex, offsetBy: -ellipsis.characters.count)
var range = start..<end
while numberOfLines(truncatedText) > numberOfVisibleLines {
truncatedText.removeSubrange(range)
range = truncatedText.index(range.lowerBound, offsetBy: -1)..<truncatedText.index(range.upperBound, offsetBy: -1)
}
return truncatedText
}
// MARK: - Initialization
public init(text: String, expanded: Bool = false) {
self.fullText = text
super.init(frame: CGRect.zero)
numberOfLines = 0
updateText(text)
self.expanded = expanded
addGestureRecognizer(tapGestureRecognizer)
}
public required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Actions
func labelDidTap(_ tapGestureRecognizer: UITapGestureRecognizer) {
shortText = truncatedText
expanded ? collapse() : expand()
}
func expand() {
frame.size.height = heightForString(fullText)
updateText(fullText)
expanded = expandable
}
func collapse() {
frame.size.height = heightForString(shortText)
updateText(shortText)
expanded = false
}
fileprivate func updateText(_ string: String) {
let attributedString = NSMutableAttributedString(string: string,
attributes: LightboxConfig.InfoLabel.textAttributes)
if string.range(of: ellipsis) != nil {
let range = (string as NSString).range(of: ellipsis)
attributedString.addAttribute(NSForegroundColorAttributeName,
value: LightboxConfig.InfoLabel.ellipsisColor, range: range)
}
attributedText = attributedString
}
// MARK: - Helper methods
fileprivate func heightForString(_ string: String) -> CGFloat {
return string.boundingRect(
with: CGSize(width: bounds.size.width, height: CGFloat.greatestFiniteMagnitude),
options: [.usesLineFragmentOrigin, .usesFontLeading],
attributes: [NSFontAttributeName: font],
context: nil).height
}
fileprivate func numberOfLines(_ string: String) -> Int {
let lineHeight = "A".size(attributes: [NSFontAttributeName: font]).height
let totalHeight = heightForString(string)
return Int(totalHeight / lineHeight)
}
}
// MARK: - LayoutConfigurable
extension InfoLabel: LayoutConfigurable {
public func configureLayout() {
shortText = truncatedText
expanded ? expand() : collapse()
}
}
+31
View File
@@ -0,0 +1,31 @@
import UIKit
class LoadingIndicator: UIView {
var indicator: UIActivityIndicatorView!
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 60, height: 60))
backgroundColor = UIColor.darkGray
layer.cornerRadius = bounds.size.width / 2
clipsToBounds = true
alpha = 0
indicator = UIActivityIndicatorView()
indicator.activityIndicatorViewStyle = .whiteLarge
indicator.startAnimating()
addSubview(indicator)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layoutSubviews() {
super.layoutSubviews()
indicator.center = CGPoint(x: bounds.size.width/2, y: bounds.size.height/2)
}
}
+223
View File
@@ -0,0 +1,223 @@
import UIKit
protocol PageViewDelegate: class {
func pageViewDidZoom(_ pageView: PageView)
func remoteImageDidLoad(_ image: UIImage?, imageView: UIImageView)
func pageView(_ pageView: PageView, didTouchPlayButton videoURL: URL)
func pageViewDidTouch(_ pageView: PageView)
}
class PageView: UIScrollView {
lazy var imageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
imageView.isUserInteractionEnabled = true
return imageView
}()
lazy var playButton: UIButton = {
let button = UIButton(type: .custom)
button.frame.size = CGSize(width: 60, height: 60)
button.setBackgroundImage(AssetManager.image("lightbox_play"), for: UIControlState())
button.addTarget(self, action: #selector(playButtonTouched(_:)), for: .touchUpInside)
button.layer.shadowOffset = CGSize(width: 1, height: 1)
button.layer.shadowColor = UIColor.gray.cgColor
button.layer.masksToBounds = false
button.layer.shadowOpacity = 0.8
return button
}()
lazy var activityIndicator: LoadingIndicator = LoadingIndicator()
var image: LightboxImage
var contentFrame = CGRect.zero
weak var pageViewDelegate: PageViewDelegate?
var hasZoomed: Bool {
return zoomScale != 1.0
}
// MARK: - Initializers
init(image: LightboxImage) {
self.image = image
super.init(frame: CGRect.zero)
configure()
activityIndicator.alpha = 1
self.image.addImageTo(imageView) { [weak self] image in
guard let strongSelf = self else {
return
}
strongSelf.isUserInteractionEnabled = true
strongSelf.configureImageView()
strongSelf.pageViewDelegate?.remoteImageDidLoad(image, imageView: strongSelf.imageView)
UIView.animate(withDuration: 0.4) {
strongSelf.activityIndicator.alpha = 0
}
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Configuration
func configure() {
addSubview(imageView)
if image.videoURL != nil {
addSubview(playButton)
}
addSubview(activityIndicator)
delegate = self
isMultipleTouchEnabled = true
minimumZoomScale = LightboxConfig.Zoom.minimumScale
maximumZoomScale = LightboxConfig.Zoom.maximumScale
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action: #selector(scrollViewDoubleTapped(_:)))
doubleTapRecognizer.numberOfTapsRequired = 2
doubleTapRecognizer.numberOfTouchesRequired = 1
addGestureRecognizer(doubleTapRecognizer)
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(viewTapped(_:)))
addGestureRecognizer(tapRecognizer)
tapRecognizer.require(toFail: doubleTapRecognizer)
}
// MARK: - Recognizers
func scrollViewDoubleTapped(_ recognizer: UITapGestureRecognizer) {
let pointInView = recognizer.location(in: imageView)
let newZoomScale = zoomScale > minimumZoomScale
? minimumZoomScale
: maximumZoomScale
let width = contentFrame.size.width / newZoomScale
let height = contentFrame.size.height / newZoomScale
let x = pointInView.x - (width / 2.0)
let y = pointInView.y - (height / 2.0)
let rectToZoomTo = CGRect(x: x, y: y, width: width, height: height)
zoom(to: rectToZoomTo, animated: true)
}
func viewTapped(_ recognizer: UITapGestureRecognizer) {
pageViewDelegate?.pageViewDidTouch(self)
}
// MARK: - Layout
override func layoutSubviews() {
super.layoutSubviews()
activityIndicator.center = imageView.center
playButton.center = imageView.center
}
func configureImageView() {
guard let image = imageView.image else {
centerImageView()
return
}
let imageViewSize = imageView.frame.size
let imageSize = image.size
let realImageViewSize: CGSize
if imageSize.width / imageSize.height > imageViewSize.width / imageViewSize.height {
realImageViewSize = CGSize(
width: imageViewSize.width,
height: imageViewSize.width / imageSize.width * imageSize.height)
} else {
realImageViewSize = CGSize(
width: imageViewSize.height / imageSize.height * imageSize.width,
height: imageViewSize.height)
}
imageView.frame = CGRect(origin: CGPoint.zero, size: realImageViewSize)
centerImageView()
}
func centerImageView() {
let boundsSize = contentFrame.size
var imageViewFrame = imageView.frame
if imageViewFrame.size.width < boundsSize.width {
imageViewFrame.origin.x = (boundsSize.width - imageViewFrame.size.width) / 2.0
} else {
imageViewFrame.origin.x = 0.0
}
if imageViewFrame.size.height < boundsSize.height {
imageViewFrame.origin.y = (boundsSize.height - imageViewFrame.size.height) / 2.0
} else {
imageViewFrame.origin.y = 0.0
}
imageView.frame = imageViewFrame
}
// MARK: - Action
func playButtonTouched(_ button: UIButton) {
guard let videoURL = image.videoURL else { return }
pageViewDelegate?.pageView(self, didTouchPlayButton: videoURL as URL)
}
// MARK: - Controls
func makeActivityIndicator() -> UIActivityIndicatorView {
let view = UIActivityIndicatorView(activityIndicatorStyle: .white)
LightboxConfig.LoadingIndicator.configure?(view)
view.startAnimating()
return view
}
}
// MARK: - LayoutConfigurable
extension PageView: LayoutConfigurable {
func configureLayout() {
contentFrame = frame
contentSize = frame.size
imageView.frame = frame
zoomScale = minimumZoomScale
configureImageView()
}
}
// MARK: - UIScrollViewDelegate
extension PageView: UIScrollViewDelegate {
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
centerImageView()
pageViewDelegate?.pageViewDidZoom(self)
}
}