Compare commits

...

44 Commits

Author SHA1 Message Date
Grigory Ulanov 671e157f06 custom headers settings added 2017-01-09 16:48:44 +03:00
Grigory Ulanov 5d342d7a3b fixes 2016-12-05 13:40:47 +03:00
Grigory Ulanov 8366afeb44 Merge branch 'swift3' of https://github.com/GrigoryUlanov/SKPhotoBrowser into swift3 2016-11-21 17:37:59 +03:00
Grigory Ulanov b8156c7d6b swipe closw fixed 2016-11-21 17:37:55 +03:00
Grigory Ulanov f67abbc97a Merge branch 'swift3' of https://github.com/GrigoryUlanov/SKPhotoBrowser into swift3 2016-11-15 23:34:55 +03:00
Grigory Ulanov 8be7dfa8c3 resizableImageView fixed 2016-11-15 23:34:42 +03:00
Grigory Ulanov 08b857a00b didPresentPage fixed 2016-11-14 21:11:27 +03:00
Grigory Ulanov 378973db1d modalPresentationStyle changed to overFullScreen 2016-11-11 13:52:16 +03:00
Grigory Ulanov b49fa26960 in call status bar fix 2016-11-09 18:24:27 +03:00
Grigory Ulanov 660ebf5a31 bar color 2016-11-07 12:33:42 +03:00
Grigory Ulanov 36e86dad64 navbar animation fix 2016-11-03 16:54:09 +03:00
Grigory Ulanov 29f3643a7a face up fixes 2016-11-01 10:49:39 +03:00
Grigory Ulanov 828fe43d5a status bar fix 2016-11-01 09:45:23 +03:00
Grigory Ulanov 5f7f93cb6c fixes 2016-10-30 03:05:30 +03:00
Grigory Ulanov 5c473baa98 fix 2016-10-30 02:56:41 +03:00
Grigory Ulanov cebe57d401 status bar height 2016-10-30 02:53:53 +03:00
Grigory Ulanov 700264f1b9 animation and status bar last fixes 2016-10-30 02:51:12 +03:00
Grigory Ulanov ef66295f32 dismiss fix 2016-10-30 02:10:23 +03:00
Grigory Ulanov 78da87c180 close fixes 2016-10-30 01:55:33 +03:00
Grigory Ulanov 92734dd5d3 animation fixes 2016-10-30 01:28:25 +03:00
Grigory Ulanov 21721e4445 status bar only partret 2016-10-30 01:13:19 +03:00
Grigory Ulanov 5062b3821a status bar prefered fixed 2016-10-30 01:04:40 +03:00
Grigory Ulanov dee700fbea status bar 2016-10-30 01:03:51 +03:00
Grigory Ulanov 53436a2288 status bar fixes 2016-10-30 00:48:14 +03:00
Grigory Ulanov ae76f6487a layout fixes 2016-10-30 00:33:38 +03:00
Grigory Ulanov af3d342eb1 frame fix 2016-10-29 22:50:06 +03:00
Grigory Ulanov b346984634 done button 2016-10-29 22:24:47 +03:00
Grigory Ulanov dcd663a841 fix 2016-10-26 23:27:25 +03:00
Grigory Ulanov 2ba8a3c60d light status bar 2016-10-26 23:22:53 +03:00
Grigory Ulanov 7db1d4d277 status bar returned 2016-10-26 23:15:55 +03:00
Grigory Ulanov 1ce00437d4 status bar 2016-10-26 22:24:56 +03:00
Grigory Ulanov 3dc46dd011 fade max 0.6 2016-10-14 10:21:05 +03:00
Grigory Ulanov 17f8af1f62 toolbar frame 2016-10-14 04:02:14 +03:00
Grigory Ulanov c665147348 dismiss fixes 2016-10-14 03:53:38 +03:00
Grigory Ulanov b7a030506b swift 3 migration done 2016-10-12 09:31:37 +03:00
keishi suzuki 4dc2f9717f Merge pull request #143 from madsb/swift3
Swift 3 conversion
2016-09-13 11:10:50 +09:00
Mads Bjerre 7a4a26e42f Convert example to Swift 3 2016-09-09 20:02:54 +02:00
Mads Bjerre b022bd0c44 Not clear, black! 2016-09-09 20:01:55 +02:00
Mads Bjerre 985e9d31fe Fix typo 2016-09-09 19:37:20 +02:00
Mads Bjerre 107ad78354 Fix crashing error 2016-09-09 19:33:08 +02:00
Mads Bjerre d42a43a7ea Fix warning 2016-09-09 19:32:26 +02:00
Mads Bjerre 85d58f5888 Fix errors 2016-09-09 12:45:36 +02:00
Mads Bjerre b595a5beb7 Update to recommended project settings 2016-09-09 12:33:32 +02:00
Mads Bjerre c719c4363f Auto conversion to Swift 3 syntax 2016-09-09 12:33:11 +02:00
30 changed files with 756 additions and 515 deletions

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
0A6BA1F31DAE0E2700778221 /* SKNavigationBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BA1F21DAE0E2700778221 /* SKNavigationBar.swift */; };
210E53ED1C986D3A008DD5E3 /* UIView+Radius.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210E53EC1C986D3A008DD5E3 /* UIView+Radius.swift */; };
210E53EF1C986D57008DD5E3 /* UIImage+Rotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 210E53EE1C986D57008DD5E3 /* UIImage+Rotation.swift */; };
26C97AD51D0EB6870039F6CB /* SKCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26C97AD41D0EB6870039F6CB /* SKCache.swift */; };
@ -44,6 +45,7 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0A6BA1F21DAE0E2700778221 /* SKNavigationBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SKNavigationBar.swift; sourceTree = "<group>"; };
210E53EC1C986D3A008DD5E3 /* UIView+Radius.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIView+Radius.swift"; path = "extensions/UIView+Radius.swift"; sourceTree = "<group>"; };
210E53EE1C986D57008DD5E3 /* UIImage+Rotation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+Rotation.swift"; path = "extensions/UIImage+Rotation.swift"; sourceTree = "<group>"; };
26C97AD41D0EB6870039F6CB /* SKCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SKCache.swift; sourceTree = "<group>"; };
@ -135,6 +137,7 @@
8909B53F1BC791510060A053 /* SKPhoto.swift */,
8909B5411BC791510060A053 /* SKPhotoBrowser.swift */,
89C24A811D657AD1005F09A9 /* SKPhotoBrowserOptions.swift */,
0A6BA1F21DAE0E2700778221 /* SKNavigationBar.swift */,
890A6F1F1D5D9E53003B01F0 /* SKToolbar.swift */,
8909B5331BC791280060A053 /* SKPhotoBrowser.h */,
8917B1AF1D5A13DE000CE1C4 /* SKPhotoBrowserDelegate.swift */,
@ -215,7 +218,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0730;
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = suzuki_keishi;
TargetAttributes = {
8909B52F1BC791280060A053 = {
@ -300,6 +303,7 @@
8917B1B41D5A14B0000CE1C4 /* SKButtons.swift in Sources */,
89C24A821D657AD1005F09A9 /* SKPhotoBrowserOptions.swift in Sources */,
26C97AD51D0EB6870039F6CB /* SKCache.swift in Sources */,
0A6BA1F31DAE0E2700778221 /* SKNavigationBar.swift in Sources */,
210E53EF1C986D57008DD5E3 /* UIImage+Rotation.swift in Sources */,
8909B5431BC791510060A053 /* SKCaptionView.swift in Sources */,
8909B5491BC791510060A053 /* SKPhotoBrowser.swift in Sources */,
@ -340,8 +344,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";
@ -388,8 +394,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";
@ -409,6 +417,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
VERSIONING_SYSTEM = "apple-generic";
@ -420,6 +429,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -432,7 +442,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
@ -440,6 +450,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
@ -451,7 +462,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.keishi.suzuki.SKPhotoBrowser;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
};
name = Release;
};

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0700"
LastUpgradeVersion = "0800"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -10,12 +10,13 @@ import UIKit
@objc public protocol SKPhotoBrowserAnimatorDelegate {
func willPresent(browser: SKPhotoBrowser)
func willDismiss(browser: SKPhotoBrowser)
func willPresent(_ browser: SKPhotoBrowser)
func willDismiss(_ browser: SKPhotoBrowser, sender: UIView?)
}
class SKAnimator: NSObject, SKPhotoBrowserAnimatorDelegate {
var resizableImageView: UIImageView?
var parentViewController: UIViewController?
var senderOriginImage: UIImage!
var senderViewOriginalFrame: CGRect = .zero
@ -24,7 +25,7 @@ class SKAnimator: NSObject, SKPhotoBrowserAnimatorDelegate {
var finalImageViewFrame: CGRect = .zero
var bounceAnimation: Bool = false
var animationDuration: NSTimeInterval {
var animationDuration: TimeInterval {
if SKPhotoBrowserOptions.bounceAnimation {
return 0.5
}
@ -37,8 +38,8 @@ class SKAnimator: NSObject, SKPhotoBrowserAnimatorDelegate {
return 1
}
func willPresent(browser: SKPhotoBrowser) {
guard let appWindow = UIApplication.sharedApplication().delegate?.window else {
func willPresent(_ browser: SKPhotoBrowser) {
guard let appWindow = UIApplication.shared.delegate?.window else {
return
}
guard let window = appWindow else {
@ -70,23 +71,20 @@ class SKAnimator: NSObject, SKPhotoBrowserAnimatorDelegate {
presentAnimation(browser)
}
func willDismiss(browser: SKPhotoBrowser) {
guard let sender = browser.delegate?.viewForPhoto?(browser, index: browser.currentPageIndex),
image = browser.photoAtIndex(browser.currentPageIndex).underlyingImage,
scrollView = browser.pageDisplayedAtIndex(browser.currentPageIndex) else {
senderViewForAnimation?.hidden = false
browser.dismissPhotoBrowser(animated: false)
func willDismiss(_ browser: SKPhotoBrowser, sender: UIView?) {
guard let sender = sender, let image = browser.photoAtIndex(browser.currentPageIndex).underlyingImage,
let scrollView = browser.pageDisplayedAtIndex(browser.currentPageIndex) else {
self.resizableImageView?.removeFromSuperview()
browser.dismissPhotoBrowser(animated: true)
return
}
senderViewForAnimation = sender
browser.view.hidden = true
browser.backgroundView.hidden = false
browser.backgroundView.alpha = 1
browser.view.isHidden = true
senderViewOriginalFrame = calcOriginFrame(sender)
let photo = browser.photoAtIndex(browser.currentPageIndex)
let contentOffset = scrollView.contentOffset
let scrollFrame = scrollView.photoImageView.frame
@ -97,34 +95,35 @@ class SKAnimator: NSObject, SKPhotoBrowserAnimatorDelegate {
width: scrollFrame.width,
height: scrollFrame.height)
// resizableImageView.image = scrollView.photo?.underlyingImage?.rotateImageByOrientation()
resizableImageView!.image = image.rotateImageByOrientation()
resizableImageView!.frame = frame
resizableImageView!.alpha = 1.0
resizableImageView!.clipsToBounds = true
resizableImageView!.contentMode = photo.contentMode
if let view = senderViewForAnimation where view.layer.cornerRadius != 0 {
if let view = senderViewForAnimation, view.layer.cornerRadius != 0 {
let duration = (animationDuration * Double(animationDamping))
resizableImageView!.layer.masksToBounds = true
resizableImageView!.addCornerRadiusAnimation(0, to: view.layer.cornerRadius, duration: duration)
}
parentViewController?.view.insertSubview(resizableImageView!, at: 1)
dismissAnimation(browser)
}
}
private extension SKAnimator {
func calcOriginFrame(sender: UIView) -> CGRect {
if let senderViewOriginalFrameTemp = sender.superview?.convertRect(sender.frame, toView:nil) {
func calcOriginFrame(_ sender: UIView) -> CGRect {
if let senderViewOriginalFrameTemp = sender.superview?.convert(sender.frame, to:nil) {
return senderViewOriginalFrameTemp
} else if let senderViewOriginalFrameTemp = sender.layer.superlayer?.convertRect(sender.frame, toLayer: nil) {
} else if let senderViewOriginalFrameTemp = sender.layer.superlayer?.convert(sender.frame, to: nil) {
return senderViewOriginalFrameTemp
} else {
return .zero
}
}
func calcFinalFrame(imageRatio: CGFloat) -> CGRect {
func calcFinalFrame(_ imageRatio: CGFloat) -> CGRect {
if SKMesurement.screenRatio < imageRatio {
let width = SKMesurement.screenWidth
let height = width / imageRatio
@ -140,16 +139,16 @@ private extension SKAnimator {
}
private extension SKAnimator {
func presentAnimation(browser: SKPhotoBrowser, completion: (Void -> Void)? = nil) {
browser.view.hidden = true
func presentAnimation(_ browser: SKPhotoBrowser, completion: ((Void) -> Void)? = nil) {
browser.view.isHidden = true
browser.view.alpha = 0.0
UIView.animateWithDuration(
animationDuration,
UIView.animate(
withDuration: animationDuration,
delay: 0,
usingSpringWithDamping:animationDamping,
initialSpringVelocity:0,
options:.CurveEaseInOut,
options:UIViewAnimationOptions(),
animations: {
browser.showButtons()
browser.backgroundView.alpha = 1.0
@ -157,21 +156,21 @@ private extension SKAnimator {
self.resizableImageView?.frame = self.finalImageViewFrame
},
completion: { (Bool) -> Void in
browser.view.hidden = false
browser.view.isHidden = false
browser.view.alpha = 1.0
browser.backgroundView.hidden = true
browser.backgroundView.isHidden = true
self.resizableImageView?.alpha = 0.0
})
}
func dismissAnimation(browser: SKPhotoBrowser, completion: (Void -> Void)? = nil) {
UIView.animateWithDuration(
animationDuration,
func dismissAnimation(_ browser: SKPhotoBrowser, completion: ((Void) -> Void)? = nil) {
UIView.animate(
withDuration: animationDuration,
delay:0,
usingSpringWithDamping:animationDamping,
initialSpringVelocity:0,
options:.CurveEaseInOut,
options:UIViewAnimationOptions(),
animations: {
browser.backgroundView.alpha = 0.0

View File

@ -9,7 +9,7 @@
import Foundation
// helpers which often used
private let bundle = NSBundle(forClass: SKPhotoBrowser.self)
private let bundle = Bundle(for: SKPhotoBrowser.self)
class SKButton: UIButton {
var showFrame: CGRect!
@ -17,7 +17,7 @@ class SKButton: UIButton {
var insets: UIEdgeInsets {
return UI_USER_INTERFACE_IDIOM() == .Phone
return UI_USER_INTERFACE_IDIOM() == .phone
? UIEdgeInsets(top: 15.25, left: 15.25, bottom: 15.25, right: 15.25) : UIEdgeInsets(top: 12, left: 12, bottom: 12, right: 12)
}
var size: CGSize = CGSize(width: 44, height: 44)
@ -25,21 +25,21 @@ class SKButton: UIButton {
var buttonTopOffset: CGFloat { return 5 }
func setup(imageName: String) {
backgroundColor = .clearColor()
func setup(_ imageName: String) {
backgroundColor = UIColor.clear
imageEdgeInsets = insets
// clipsToBounds = true
translatesAutoresizingMaskIntoConstraints = true
autoresizingMask = [.FlexibleBottomMargin, .FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleTopMargin]
autoresizingMask = [.flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin]
let image = UIImage(named: "SKPhotoBrowser.bundle/images/\(imageName)",
inBundle: bundle, compatibleWithTraitCollection: nil) ?? UIImage()
setImage(image, forState: .Normal)
in: bundle, compatibleWith: nil) ?? UIImage()
setImage(image, for: UIControlState())
}
func updateFrame() { }
func setFrameSize(size: CGSize) {
func setFrameSize(_ size: CGSize) {
let newRect = CGRect(x: margin, y: buttonTopOffset, width: size.width, height: size.height)
self.frame = newRect
showFrame = newRect
@ -80,7 +80,7 @@ class SKDeleteButton: SKButton {
override func updateFrame() {
}
override func setFrameSize(size: CGSize) {
override func setFrameSize(_ size: CGSize) {
let newRect = CGRect(x: SKMesurement.screenWidth - size.width, y: buttonTopOffset, width: size.width, height: size.height)
self.frame = newRect
showFrame = newRect

View File

@ -8,15 +8,15 @@
import UIKit
public class SKCache {
public static let sharedCache = SKCache()
public var imageCache: SKCacheable
open class SKCache {
open static let sharedCache = SKCache()
open var imageCache: SKCacheable
init() {
self.imageCache = SKDefaultImageCache()
}
public func imageForKey(key: String) -> UIImage? {
open func imageForKey(_ key: String) -> UIImage? {
guard let cache = imageCache as? SKImageCacheable else {
return nil
}
@ -24,7 +24,7 @@ public class SKCache {
return cache.imageForKey(key)
}
public func setImage(image: UIImage, forKey key: String) {
open func setImage(_ image: UIImage, forKey key: String) {
guard let cache = imageCache as? SKImageCacheable else {
return
}
@ -32,7 +32,7 @@ public class SKCache {
cache.setImage(image, forKey: key)
}
public func removeImageForKey(key: String) {
open func removeImageForKey(_ key: String) {
guard let cache = imageCache as? SKImageCacheable else {
return
}
@ -40,7 +40,7 @@ public class SKCache {
cache.removeImageForKey(key)
}
public func imageForRequest(request: NSURLRequest) -> UIImage? {
open func imageForRequest(_ request: URLRequest) -> UIImage? {
guard let cache = imageCache as? SKRequestResponseCacheable else {
return nil
}
@ -51,31 +51,31 @@ public class SKCache {
return nil
}
public func setImageData(data: NSData, response: NSURLResponse, request: NSURLRequest) {
open func setImageData(_ data: Data, response: URLResponse, request: URLRequest) {
guard let cache = imageCache as? SKRequestResponseCacheable else {
return
}
let cachedResponse = NSCachedURLResponse(response: response, data: data)
let cachedResponse = CachedURLResponse(response: response, data: data)
cache.storeCachedResponse(cachedResponse, forRequest: request)
}
}
class SKDefaultImageCache: SKImageCacheable {
var cache: NSCache
var cache: NSCache<AnyObject, AnyObject>
init() {
cache = NSCache()
}
func imageForKey(key: String) -> UIImage? {
return cache.objectForKey(key) as? UIImage
func imageForKey(_ key: String) -> UIImage? {
return cache.object(forKey: key as AnyObject) as? UIImage
}
func setImage(image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key)
func setImage(_ image: UIImage, forKey key: String) {
cache.setObject(image, forKey: key as AnyObject)
}
func removeImageForKey(key: String) {
cache.removeObjectForKey(key)
func removeImageForKey(_ key: String) {
cache.removeObject(forKey: key as AnyObject)
}
}

View File

@ -10,12 +10,12 @@ import UIKit.UIImage
public protocol SKCacheable {}
public protocol SKImageCacheable: SKCacheable {
func imageForKey(key: String) -> UIImage?
func setImage(image: UIImage, forKey key: String)
func removeImageForKey(key: String)
func imageForKey(_ key: String) -> UIImage?
func setImage(_ image: UIImage, forKey key: String)
func removeImageForKey(_ key: String)
}
public protocol SKRequestResponseCacheable: SKCacheable {
func cachedResponseForRequest(request: NSURLRequest) -> NSCachedURLResponse?
func storeCachedResponse(cachedResponse: NSCachedURLResponse, forRequest request: NSURLRequest)
func cachedResponseForRequest(_ request: URLRequest) -> CachedURLResponse?
func storeCachedResponse(_ cachedResponse: CachedURLResponse, forRequest request: URLRequest)
}

View File

@ -7,11 +7,31 @@
//
import UIKit
fileprivate func < <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l < r
case (nil, _?):
return true
default:
return false
}
}
public class SKCaptionView: UIView {
private var photo: SKPhotoProtocol?
private var photoLabel: UILabel!
private var photoLabelPadding: CGFloat = 10
fileprivate func > <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
switch (lhs, rhs) {
case let (l?, r?):
return l > r
default:
return rhs < lhs
}
}
open class SKCaptionView: UIView {
fileprivate var photo: SKPhotoProtocol?
fileprivate var photoLabel: UILabel!
fileprivate var photoLabelPadding: CGFloat = 10
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
@ -22,13 +42,13 @@ public class SKCaptionView: UIView {
}
public convenience init(photo: SKPhotoProtocol) {
let screenBound = UIScreen.mainScreen().bounds
let screenBound = UIScreen.main.bounds
self.init(frame: CGRect(x: 0, y: 0, width: screenBound.size.width, height: screenBound.size.height))
self.photo = photo
setup()
}
public override func sizeThatFits(size: CGSize) -> CGSize {
open override func sizeThatFits(_ size: CGSize) -> CGSize {
guard let text = photoLabel.text else {
return CGSize.zero
}
@ -41,7 +61,7 @@ public class SKCaptionView: UIView {
let height: CGFloat = photoLabel.font.lineHeight * CGFloat(photoLabel.numberOfLines)
let attributedText = NSAttributedString(string: text, attributes: [NSFontAttributeName: font])
let textSize = attributedText.boundingRectWithSize(CGSize(width: width, height: height), options: .UsesLineFragmentOrigin, context: nil).size
let textSize = attributedText.boundingRect(with: CGSize(width: width, height: height), options: .usesLineFragmentOrigin, context: nil).size
return CGSize(width: textSize.width, height: textSize.height + photoLabelPadding * 2)
}
@ -49,8 +69,8 @@ public class SKCaptionView: UIView {
private extension SKCaptionView {
func setup() {
opaque = false
autoresizingMask = [.FlexibleWidth, .FlexibleTopMargin, .FlexibleRightMargin, .FlexibleLeftMargin]
isOpaque = false
autoresizingMask = [.flexibleWidth, .flexibleTopMargin, .flexibleRightMargin, .flexibleLeftMargin]
// setup photoLabel
setupPhotoLabel()
@ -58,16 +78,16 @@ private extension SKCaptionView {
func setupPhotoLabel() {
photoLabel = UILabel(frame: CGRect(x: photoLabelPadding, y: 0, width: bounds.size.width - (photoLabelPadding * 2), height: bounds.size.height))
photoLabel.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
photoLabel.opaque = false
photoLabel.backgroundColor = .clearColor()
photoLabel.textColor = .whiteColor()
photoLabel.textAlignment = .Center
photoLabel.lineBreakMode = .ByTruncatingTail
photoLabel.autoresizingMask = [.flexibleWidth, .flexibleHeight]
photoLabel.isOpaque = false
photoLabel.backgroundColor = UIColor.clear
photoLabel.textColor = UIColor.white
photoLabel.textAlignment = .center
photoLabel.lineBreakMode = .byTruncatingTail
photoLabel.numberOfLines = 3
photoLabel.shadowColor = UIColor(white: 0.0, alpha: 0.5)
photoLabel.shadowOffset = CGSize(width: 0.0, height: 1.0)
photoLabel.font = UIFont.systemFontOfSize(17.0)
photoLabel.font = UIFont.systemFont(ofSize: 17.0)
photoLabel.text = photo?.caption
addSubview(photoLabel)
}

View File

@ -9,8 +9,8 @@
import UIKit
@objc protocol SKDetectingImageViewDelegate {
func handleImageViewSingleTap(touchPoint: CGPoint)
func handleImageViewDoubleTap(touchPoint: CGPoint)
func handleImageViewSingleTap(_ touchPoint: CGPoint)
func handleImageViewDoubleTap(_ touchPoint: CGPoint)
}
class SKDetectingImageView: UIImageView {
@ -26,25 +26,25 @@ class SKDetectingImageView: UIImageView {
setup()
}
func handleDoubleTap(recognizer: UITapGestureRecognizer) {
delegate?.handleImageViewDoubleTap(recognizer.locationInView(self))
func handleDoubleTap(_ recognizer: UITapGestureRecognizer) {
delegate?.handleImageViewDoubleTap(recognizer.location(in: self))
}
func handleSingleTap(recognizer: UITapGestureRecognizer) {
delegate?.handleImageViewSingleTap(recognizer.locationInView(self))
func handleSingleTap(_ recognizer: UITapGestureRecognizer) {
delegate?.handleImageViewSingleTap(recognizer.location(in: self))
}
}
private extension SKDetectingImageView {
func setup() {
userInteractionEnabled = true
isUserInteractionEnabled = true
let doubleTap = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(_:)))
doubleTap.numberOfTapsRequired = 2
addGestureRecognizer(doubleTap)
let singleTap = UITapGestureRecognizer(target: self, action: #selector(handleSingleTap(_:)))
singleTap.requireGestureRecognizerToFail(doubleTap)
singleTap.require(toFail: doubleTap)
addGestureRecognizer(singleTap)
}
}
}

View File

@ -9,17 +9,17 @@
import UIKit
@objc protocol SKDetectingViewDelegate {
func handleSingleTap(view: UIView, touch: UITouch)
func handleDoubleTap(view: UIView, touch: UITouch)
func handleSingleTap(_ view: UIView, touch: UITouch)
func handleDoubleTap(_ view: UIView, touch: UITouch)
}
class SKDetectingView: UIView {
weak var delegate: SKDetectingViewDelegate?
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
super.touchesEnded(touches, withEvent: event)
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
defer {
nextResponder()
_ = next
}
guard let touch = touches.first else {
@ -32,11 +32,11 @@ class SKDetectingView: UIView {
}
}
func handleSingleTap(touch: UITouch) {
func handleSingleTap(_ touch: UITouch) {
delegate?.handleSingleTap(self, touch: touch)
}
func handleDoubleTap(touch: UITouch) {
func handleDoubleTap(_ touch: UITouch) {
delegate?.handleDoubleTap(self, touch: touch)
}
}

View File

@ -16,6 +16,6 @@ class SKIndicatorView: UIActivityIndicatorView {
override init(frame: CGRect) {
super.init(frame: frame)
center = CGPoint(x: frame.width / 2, y: frame.height / 2)
activityIndicatorViewStyle = .WhiteLarge
activityIndicatorViewStyle = .whiteLarge
}
}

View File

@ -9,14 +9,14 @@
import UIKit
// MARK: - SKLocalPhoto
public class SKLocalPhoto: NSObject, SKPhotoProtocol {
open class SKLocalPhoto: NSObject, SKPhotoProtocol {
public var underlyingImage: UIImage!
public var photoURL: String!
public var contentMode: UIViewContentMode = .ScaleToFill
public var shouldCachePhotoURLImage: Bool = false
public var caption: String!
public var index: Int = 0
open var underlyingImage: UIImage!
open var photoURL: String!
open var contentMode: UIViewContentMode = .scaleToFill
open var shouldCachePhotoURLImage: Bool = false
open var caption: String!
open var index: Int = 0
override init() {
super.init()
@ -33,9 +33,9 @@ public class SKLocalPhoto: NSObject, SKPhotoProtocol {
underlyingImage = holder
}
public func checkCache() {}
open func checkCache() {}
public func loadUnderlyingImageAndNotify() {
open func loadUnderlyingImageAndNotify() {
if underlyingImage != nil && photoURL == nil {
loadUnderlyingImageComplete()
@ -43,8 +43,8 @@ public class SKLocalPhoto: NSObject, SKPhotoProtocol {
if photoURL != nil {
// Fetch Image
if NSFileManager.defaultManager().fileExistsAtPath(photoURL) {
if let data = NSFileManager.defaultManager().contentsAtPath(photoURL) {
if FileManager.default.fileExists(atPath: photoURL) {
if let data = FileManager.default.contents(atPath: photoURL) {
self.loadUnderlyingImageComplete()
if let image = UIImage(data: data) {
self.underlyingImage = image
@ -55,16 +55,16 @@ public class SKLocalPhoto: NSObject, SKPhotoProtocol {
}
}
public func loadUnderlyingImageComplete() {
NSNotificationCenter.defaultCenter().postNotificationName(SKPHOTO_LOADING_DID_END_NOTIFICATION, object: self)
open func loadUnderlyingImageComplete() {
NotificationCenter.default.post(name: Notification.Name(rawValue: SKPHOTO_LOADING_DID_END_NOTIFICATION), object: self)
}
// MARK: - class func
public class func photoWithImageURL(url: String) -> SKLocalPhoto {
open class func photoWithImageURL(_ url: String) -> SKLocalPhoto {
return SKLocalPhoto(url: url)
}
public class func photoWithImageURL(url: String, holder: UIImage?) -> SKLocalPhoto {
open class func photoWithImageURL(_ url: String, holder: UIImage?) -> SKLocalPhoto {
return SKLocalPhoto(url: url, holder: holder)
}
}

View File

@ -10,19 +10,19 @@ import Foundation
import UIKit
struct SKMesurement {
static let isPhone: Bool = UIDevice.currentDevice().userInterfaceIdiom == .Phone
static let isPad: Bool = UIDevice.currentDevice().userInterfaceIdiom == .Pad
static let isPhone: Bool = UIDevice.current.userInterfaceIdiom == .phone
static let isPad: Bool = UIDevice.current.userInterfaceIdiom == .pad
static var statusBarH: CGFloat {
return UIApplication.sharedApplication().statusBarFrame.height
return UIApplication.shared.statusBarFrame.height
}
static var screenHeight: CGFloat {
return UIScreen.mainScreen().bounds.height
return UIScreen.main.bounds.height
}
static var screenWidth: CGFloat {
return UIScreen.mainScreen().bounds.width
return UIScreen.main.bounds.width
}
static var screenScale: CGFloat {
return UIScreen.mainScreen().scale
return UIScreen.main.scale
}
static var screenRatio: CGFloat {
return screenWidth / screenHeight

View File

@ -0,0 +1,120 @@
//
// SKNavigationBar.swift
// SKPhotoBrowser
//
// Created by Григорий Уланов on 12.10.16.
// Copyright © 2016 suzuki_keishi. All rights reserved.
//
import UIKit
class SKNavigationBar: UIView {
var showFrame: CGRect!
var hideFrame: CGRect!
private static let toolBarHeight: CGFloat = 44.0
fileprivate weak var browser: SKPhotoBrowser?
private var countLabel: UILabel?
private var doneButton: UIButton?
var onDoneTap: (() -> Void)?
var isStatusBarHidden: Bool = false {
didSet {
if let bounds = superview?.bounds {
updateFrame(bounds.size)
}
}
}
private var isBigStatusBar: Bool {
return statusBarHeight > 20 ? true : false
}
private var statusBarHeight: CGFloat {
return UIApplication.shared.statusBarFrame.height
}
convenience init(browser: SKPhotoBrowser) {
self.init(frame: CGRect.zero)
self.browser = browser
backgroundColor = UIColor.black.withAlphaComponent(0.65)
countLabel = UILabel()
countLabel?.font = UIFont.boldSystemFont(ofSize: 18)
countLabel?.textColor = UIColor.white
countLabel?.textAlignment = .center
if let countLabel = countLabel {
addSubview(countLabel)
}
doneButton = UIButton()
doneButton?.setTitle(SKPhotoBrowserOptions.navigationBarDoneTitle, for: .normal)
doneButton?.setTitleColor(UIColor.white, for: .normal)
doneButton?.addTarget(self, action: #selector(doneButtonAction), for: .touchUpInside)
if let doneButton = doneButton {
addSubview(doneButton)
}
}
@objc private func doneButtonAction() {
onDoneTap?()
}
func updateNavigationBar(_ currentPageIndex: Int) {
guard let browser = browser else { return }
if browser.numberOfPhotos > 1 {
self.countLabel?.text = "\(currentPageIndex + 1) \(SKPhotoBrowserOptions.navigationBarCounterSepatator) \(browser.numberOfPhotos)"
} else {
self.countLabel?.text = nil
}
}
override func layoutSubviews() {
super.layoutSubviews()
if !isStatusBarHidden {
countLabel?.frame = CGRect(x: 0,
y: isBigStatusBar ? 0 : statusBarHeight,
width: bounds.width,
height: isBigStatusBar ? bounds.height : bounds.height - statusBarHeight)
doneButton?.frame = CGRect(x: 0,
y: isBigStatusBar ? 0 : statusBarHeight,
width: 85,
height: isBigStatusBar ? bounds.height : bounds.height - statusBarHeight)
} else {
countLabel?.frame = bounds
doneButton?.frame = CGRect(x: 0, y: 0, width: 85, height: bounds.height)
}
}
private func setNewFrame(rect: CGRect) {
frame = rect
showFrame = rect
hideFrame = CGRect(x: rect.origin.x, y: rect.origin.y - 20, width: rect.size.width, height: rect.size.height)
layoutSubviews()
}
func updateFrame(_ parentSize: CGSize) {
var newRect: CGRect?
if !isStatusBarHidden {
newRect = CGRect(x: 0,
y: isBigStatusBar ? statusBarHeight/2 : 0,
width: parentSize.width,
height: isBigStatusBar ? SKNavigationBar.toolBarHeight : SKNavigationBar.toolBarHeight + statusBarHeight)
} else {
newRect = CGRect(x: 0, y: 0, width: parentSize.width, height: SKNavigationBar.toolBarHeight)
}
if let newRect = newRect {
setNewFrame(rect: newRect)
}
}
}

View File

@ -11,10 +11,10 @@ import Foundation
class SKPagingScrollView: UIScrollView {
let pageIndexTagOffset: Int = 1000
let sideMargin: CGFloat = 10
private var visiblePages = [SKZoomingScrollView]()
private var recycledPages = [SKZoomingScrollView]()
fileprivate var visiblePages = [SKZoomingScrollView]()
fileprivate var recycledPages = [SKZoomingScrollView]()
private weak var browser: SKPhotoBrowser?
fileprivate weak var browser: SKPhotoBrowser?
var numberOfPhotos: Int {
return browser?.photos.count ?? 0
}
@ -27,7 +27,7 @@ class SKPagingScrollView: UIScrollView {
override init(frame: CGRect) {
super.init(frame: frame)
pagingEnabled = true
isPagingEnabled = true
showsHorizontalScrollIndicator = true
showsVerticalScrollIndicator = true
}
@ -45,8 +45,8 @@ class SKPagingScrollView: UIScrollView {
recycledPages.removeAll()
}
func loadAdjacentPhotosIfNecessary(photo: SKPhotoProtocol, currentPageIndex: Int) {
guard let browser = browser, page = pageDisplayingAtPhoto(photo) else {
func loadAdjacentPhotosIfNecessary(_ photo: SKPhotoProtocol, currentPageIndex: Int) {
guard let browser = browser, let page = pageDisplayingAtPhoto(photo) else {
return
}
let pageIndex = (page.tag - pageIndexTagOffset)
@ -75,11 +75,11 @@ class SKPagingScrollView: UIScrollView {
}
}
func animate(frame: CGRect) {
func animate(_ frame: CGRect) {
setContentOffset(CGPoint(x: frame.origin.x - sideMargin, y: 0), animated: true)
}
func updateFrame(bounds: CGRect, currentPageIndex: Int) {
func updateFrame(_ bounds: CGRect, currentPageIndex: Int) {
var frame = bounds
frame.origin.x -= sideMargin
frame.size.width += (2 * sideMargin)
@ -105,7 +105,7 @@ class SKPagingScrollView: UIScrollView {
contentSize = CGSize(width: bounds.size.width * CGFloat(numberOfPhotos), height: bounds.size.height)
}
func updateContentOffset(index: Int) {
func updateContentOffset(_ index: Int) {
let pageWidth = bounds.size.width
let newOffset = CGFloat(index) * pageWidth
contentOffset = CGPoint(x: newOffset, y: 0)
@ -126,7 +126,7 @@ class SKPagingScrollView: UIScrollView {
}
let visibleSet: Set<SKZoomingScrollView> = Set(visiblePages)
let visibleSetWithoutRecycled: Set<SKZoomingScrollView> = visibleSet.subtract(recycledPages)
let visibleSetWithoutRecycled: Set<SKZoomingScrollView> = visibleSet.subtracting(recycledPages)
visiblePages = Array(visibleSetWithoutRecycled)
while recycledPages.count > 2 {
@ -157,7 +157,7 @@ class SKPagingScrollView: UIScrollView {
}
}
func frameForCaptionView(captionView: SKCaptionView, index: Int) -> CGRect {
func frameForCaptionView(_ captionView: SKCaptionView, index: Int) -> CGRect {
let pageFrame = frameForPageAtIndex(index)
let captionSize = captionView.sizeThatFits(CGSize(width: pageFrame.size.width, height: 0))
let navHeight = browser?.navigationController?.navigationBar.frame.size.height ?? 44
@ -165,7 +165,7 @@ class SKPagingScrollView: UIScrollView {
width: pageFrame.size.width, height: captionSize.height)
}
func pageDisplayedAtIndex(index: Int) -> SKZoomingScrollView? {
func pageDisplayedAtIndex(_ index: Int) -> SKZoomingScrollView? {
for page in visiblePages {
if page.tag - pageIndexTagOffset == index {
return page
@ -174,7 +174,7 @@ class SKPagingScrollView: UIScrollView {
return nil
}
func pageDisplayingAtPhoto(photo: SKPhotoProtocol) -> SKZoomingScrollView? {
func pageDisplayingAtPhoto(_ photo: SKPhotoProtocol) -> SKZoomingScrollView? {
for page in visiblePages {
if page.photo === photo {
return page
@ -195,15 +195,15 @@ class SKPagingScrollView: UIScrollView {
}
private extension SKPagingScrollView {
func frameForPageAtIndex(index: Int) -> CGRect {
func frameForPageAtIndex(_ index: Int) -> CGRect {
var pageFrame = bounds
pageFrame.size.width -= (2 * 10)
pageFrame.origin.x = (bounds.size.width * CGFloat(index)) + sideMargin
return pageFrame
}
func createCaptionView(index: Int) -> SKCaptionView? {
guard let photo = browser?.photoAtIndex(index) where photo.caption != nil else {
func createCaptionView(_ index: Int) -> SKCaptionView? {
guard let photo = browser?.photoAtIndex(index), photo.caption != nil else {
return nil
}
return SKCaptionView(photo: photo)

View File

@ -18,14 +18,14 @@ import UIKit
}
// MARK: - SKPhoto
public class SKPhoto: NSObject, SKPhotoProtocol {
open class SKPhoto: NSObject, SKPhotoProtocol {
public var underlyingImage: UIImage!
public var photoURL: String!
public var contentMode: UIViewContentMode = .ScaleAspectFill
public var shouldCachePhotoURLImage: Bool = false
public var caption: String!
public var index: Int = 0
open var underlyingImage: UIImage!
open var photoURL: String!
open var contentMode: UIViewContentMode = .scaleAspectFill
open var shouldCachePhotoURLImage: Bool = false
open var caption: String!
open var index: Int = 0
override init() {
super.init()
@ -47,7 +47,7 @@ public class SKPhoto: NSObject, SKPhotoProtocol {
underlyingImage = holder
}
public func checkCache() {
open func checkCache() {
guard let photoURL = photoURL else {
return
}
@ -56,7 +56,7 @@ public class SKPhoto: NSObject, SKPhotoProtocol {
}
if SKCache.sharedCache.imageCache is SKRequestResponseCacheable {
let request = NSURLRequest(URL: NSURL(string: photoURL)!)
let request = URLRequest(url: URL(string: photoURL)!)
if let img = SKCache.sharedCache.imageForRequest(request) {
underlyingImage = img
}
@ -67,7 +67,7 @@ public class SKPhoto: NSObject, SKPhotoProtocol {
}
}
public func loadUnderlyingImageAndNotify() {
open func loadUnderlyingImageAndNotify() {
if underlyingImage != nil {
loadUnderlyingImageComplete()
@ -76,27 +76,33 @@ public class SKPhoto: NSObject, SKPhotoProtocol {
if photoURL != nil {
// Fetch Image
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
if let nsURL = NSURL(string: photoURL) {
var task: NSURLSessionDataTask!
task = session.dataTaskWithURL(nsURL, completionHandler: { [weak self](response: NSData?, data: NSURLResponse?, error: NSError?) in
let session = URLSession(configuration: URLSessionConfiguration.default)
if let nsURL = URL(string: photoURL) {
var task: URLSessionDataTask!
var loadingRequest = URLRequest(url: nsURL)
if let customHeaders = SKPhotoBrowserOptions.imageLoadingCustomHeaders {
loadingRequest.allHTTPHeaderFields = customHeaders
}
task = session.dataTask(with: loadingRequest, completionHandler: { [weak self] (data, response, error) in
if let _self = self {
if error != nil {
dispatch_async(dispatch_get_main_queue()) {
DispatchQueue.main.async {
_self.loadUnderlyingImageComplete()
}
}
if let res = response, image = UIImage(data: res) {
if let data = data, let response = response, let image = UIImage(data: data) {
if _self.shouldCachePhotoURLImage {
if SKCache.sharedCache.imageCache is SKRequestResponseCacheable {
SKCache.sharedCache.setImageData(response!, response: data!, request: task.originalRequest!)
SKCache.sharedCache.setImageData(data, response: response, request: task.originalRequest!)
} else {
SKCache.sharedCache.setImage(image, forKey: _self.photoURL)
}
}
dispatch_async(dispatch_get_main_queue()) {
DispatchQueue.main.async {
_self.underlyingImage = image
_self.loadUnderlyingImageComplete()
}
@ -109,8 +115,8 @@ public class SKPhoto: NSObject, SKPhotoProtocol {
}
}
public func loadUnderlyingImageComplete() {
NSNotificationCenter.defaultCenter().postNotificationName(SKPHOTO_LOADING_DID_END_NOTIFICATION, object: self)
open func loadUnderlyingImageComplete() {
NotificationCenter.default.post(name: Notification.Name(rawValue: SKPHOTO_LOADING_DID_END_NOTIFICATION), object: self)
}
}
@ -118,15 +124,15 @@ public class SKPhoto: NSObject, SKPhotoProtocol {
// MARK: - Static Function
extension SKPhoto {
public static func photoWithImage(image: UIImage) -> SKPhoto {
public static func photoWithImage(_ image: UIImage) -> SKPhoto {
return SKPhoto(image: image)
}
public static func photoWithImageURL(url: String) -> SKPhoto {
public static func photoWithImageURL(_ url: String) -> SKPhoto {
return SKPhoto(url: url)
}
public static func photoWithImageURL(url: String, holder: UIImage?) -> SKPhoto {
public static func photoWithImageURL(_ url: String, holder: UIImage?) -> SKPhoto {
return SKPhoto(url: url, holder: holder)
}
}

View File

@ -11,41 +11,54 @@ import UIKit
public let SKPHOTO_LOADING_DID_END_NOTIFICATION = "photoLoadingDidEndNotification"
// MARK: - SKPhotoBrowser
public class SKPhotoBrowser: UIViewController {
open class SKPhotoBrowser: UIViewController {
let pageIndexTagOffset: Int = 1000
private var closeButton: SKCloseButton!
private var deleteButton: SKDeleteButton!
private var toolbar: SKToolbar!
fileprivate var closeButton: SKCloseButton!
fileprivate var deleteButton: SKDeleteButton!
fileprivate var toolbar: SKToolbar!
fileprivate var navigationBar: SKNavigationBar!
// actions
private var activityViewController: UIActivityViewController!
private var panGesture: UIPanGestureRecognizer!
fileprivate var activityViewController: UIActivityViewController!
fileprivate var panGesture: UIPanGestureRecognizer!
// tool for controls
private var applicationWindow: UIWindow!
private lazy var pagingScrollView: SKPagingScrollView = SKPagingScrollView(frame: self.view.frame, browser: self)
fileprivate var applicationWindow: UIWindow!
fileprivate lazy var pagingScrollView: SKPagingScrollView = SKPagingScrollView(frame: self.view.frame, browser: self)
var backgroundView: UIView!
var initialPageIndex: Int = 0
var currentPageIndex: Int = 0
// status bar
private var isStatusBarHidden: Bool = false {
didSet {
setNeedsStatusBarAppearanceUpdate()
navigationBar.isStatusBarHidden = isStatusBarHidden
}
}
// for status check property
private var isEndAnimationByToolBar: Bool = true
private var isViewActive: Bool = false
private var isPerformingLayout: Bool = false
fileprivate var isEndAnimationByToolBar: Bool = true
fileprivate var isViewActive: Bool = false
fileprivate var isPerformingLayout: Bool = false
// pangesture property
private var firstX: CGFloat = 0.0
private var firstY: CGFloat = 0.0
fileprivate var firstX: CGFloat = 0.0
fileprivate var firstY: CGFloat = 0.0
// timer
private var controlVisibilityTimer: NSTimer!
fileprivate var controlVisibilityTimer: Timer!
// blocks
public var willDismissPage: ((_ animated: Bool) -> Void)?
public var didPresentPage: (() -> Void)?
// delegate
private let animator = SKAnimator()
public weak var delegate: SKPhotoBrowserDelegate?
fileprivate let animator = SKAnimator()
open weak var delegate: SKPhotoBrowserDelegate?
// photos
var photos: [SKPhotoProtocol] = [SKPhotoProtocol]()
@ -58,63 +71,68 @@ public class SKPhotoBrowser: UIViewController {
setup()
}
public override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) {
public override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: Bundle!) {
super.init(nibName: nil, bundle: nil)
setup()
}
public convenience init(photos: [SKPhotoProtocol]) {
self.init(nibName: nil, bundle: nil)
let picutres = photos.flatMap { $0 }
for photo in picutres {
let pictures = photos.flatMap { $0 }
for photo in pictures {
photo.checkCache()
self.photos.append(photo)
}
}
public convenience init(originImage: UIImage, photos: [SKPhotoProtocol], animatedFromView: UIView) {
public convenience init(originImage: UIImage, photos: [SKPhotoProtocol], animatedFromView: UIView, fromViewController: UIViewController) {
self.init(nibName: nil, bundle: nil)
animator.senderOriginImage = originImage
animator.senderViewForAnimation = animatedFromView
animator.parentViewController = fromViewController
let picutres = photos.flatMap { $0 }
for photo in picutres {
let pictures = photos.flatMap { $0 }
for photo in pictures {
photo.checkCache()
self.photos.append(photo)
}
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
NotificationCenter.default.removeObserver(self)
}
func setup() {
guard let window = UIApplication.sharedApplication().delegate?.window else {
guard let window = UIApplication.shared.delegate?.window else {
return
}
applicationWindow = window
modalPresentationCapturesStatusBarAppearance = true
modalPresentationStyle = .Custom
modalTransitionStyle = .CrossDissolve
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.handleSKPhotoLoadingDidEndNotification(_:)), name: SKPHOTO_LOADING_DID_END_NOTIFICATION, object: nil)
modalPresentationStyle = .overFullScreen
modalTransitionStyle = .crossDissolve
NotificationCenter.default.addObserver(self, selector: #selector(self.handleSKPhotoLoadingDidEndNotification(_:)), name: NSNotification.Name(rawValue: SKPHOTO_LOADING_DID_END_NOTIFICATION), object: nil)
}
// MARK: - override
override public func viewDidLoad() {
override open func viewDidLoad() {
super.viewDidLoad()
configureAppearance()
configureCloseButton()
configureDeleteButton()
configureNavigationBar()
configureToolbar()
animator.willPresent(self)
NotificationCenter.default.addObserver(self, selector: #selector(didChangeOrientation), name: .UIDeviceOrientationDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(didChangeStatusBarFrame), name: .UIApplicationDidChangeStatusBarFrame, object: nil)
}
override public func viewWillAppear(animated: Bool) {
override open func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
reloadData()
@ -124,36 +142,61 @@ public class SKPhotoBrowser: UIViewController {
i = i + 1
}
}
override public func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
func didChangeOrientation() {
isStatusBarHidden = UIApplication.shared.statusBarOrientation != .portrait
}
func didChangeStatusBarFrame() {
viewWillLayoutSubviews()
view.layoutSubviews()
viewDidLayoutSubviews()
}
open override func viewDidLayoutSubviews() {
setNeedsStatusBarAppearanceUpdate()
isPerformingLayout = true
closeButton.updateFrame()
deleteButton.updateFrame()
navigationBar.updateFrame(view.bounds.size)
pagingScrollView.updateFrame(view.bounds, currentPageIndex: currentPageIndex)
toolbar.frame = frameForToolbarAtOrientation()
// where did start
delegate?.didShowPhotoAtIndex?(currentPageIndex)
isPerformingLayout = false
super.viewDidLayoutSubviews()
}
override public func viewDidAppear(animated: Bool) {
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
isViewActive = true
setNeedsStatusBarAppearanceUpdate()
didPresentPage?()
}
open override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
open override var prefersStatusBarHidden: Bool {
return isStatusBarHidden
}
// MARK: - Notification
public func handleSKPhotoLoadingDidEndNotification(notification: NSNotification) {
open func handleSKPhotoLoadingDidEndNotification(_ notification: Notification) {
guard let photo = notification.object as? SKPhotoProtocol else {
return
}
dispatch_async(dispatch_get_main_queue(), {
guard let page = self.pagingScrollView.pageDisplayingAtPhoto(photo), photo = page.photo else {
DispatchQueue.main.async(execute: {
guard let page = self.pagingScrollView.pageDisplayingAtPhoto(photo), let photo = page.photo else {
return
}
@ -166,20 +209,22 @@ public class SKPhotoBrowser: UIViewController {
})
}
public func loadAdjacentPhotosIfNecessary(photo: SKPhotoProtocol) {
open func loadAdjacentPhotosIfNecessary(_ photo: SKPhotoProtocol) {
pagingScrollView.loadAdjacentPhotosIfNecessary(photo, currentPageIndex: currentPageIndex)
}
// MARK: - initialize / setup
public func reloadData() {
open func reloadData() {
backgroundView.backgroundColor = view.backgroundColor
performLayout()
view.setNeedsLayout()
}
public func performLayout() {
open func performLayout() {
isPerformingLayout = true
toolbar.updateToolbar(currentPageIndex)
navigationBar.updateNavigationBar(currentPageIndex)
// reset local cache
pagingScrollView.reload()
@ -193,50 +238,51 @@ public class SKPhotoBrowser: UIViewController {
isPerformingLayout = false
}
public func prepareForClosePhotoBrowser() {
open func prepareForClosePhotoBrowser() {
cancelControlHiding()
applicationWindow.removeGestureRecognizer(panGesture)
NSObject.cancelPreviousPerformRequestsWithTarget(self)
NSObject.cancelPreviousPerformRequests(withTarget: self)
}
public func dismissPhotoBrowser(animated animated: Bool, completion: (Void -> Void)? = nil) {
open func dismissPhotoBrowser(animated: Bool, completion: ((Void) -> Void)? = nil) {
prepareForClosePhotoBrowser()
if !animated {
modalTransitionStyle = .CrossDissolve
modalTransitionStyle = .crossDissolve
}
dismissViewControllerAnimated(!animated) {
dismiss(animated: !animated) {
completion?()
self.delegate?.didDismissAtPageIndex?(self.currentPageIndex)
}
}
public func determineAndClose() {
open func determineAndClose(sender: UIView?) {
delegate?.willDismissAtPageIndex?(currentPageIndex)
animator.willDismiss(self)
animator.willDismiss(self, sender: sender)
willDismissPage?(sender != nil)
}
}
// MARK: - Public Function For Customizing Buttons
public extension SKPhotoBrowser {
func updateCloseButton(image: UIImage, size: CGSize? = nil) {
func updateCloseButton(_ image: UIImage, size: CGSize? = nil) {
if closeButton == nil {
configureCloseButton()
}
closeButton.setImage(image, forState: .Normal)
closeButton.setImage(image, for: UIControlState())
if let size = size {
closeButton.setFrameSize(size)
}
}
func updateDeleteButton(image: UIImage, size: CGSize? = nil) {
func updateDeleteButton(_ image: UIImage, size: CGSize? = nil) {
if deleteButton == nil {
configureDeleteButton()
}
deleteButton.setImage(image, forState: .Normal)
deleteButton.setImage(image, for: UIControlState())
if let size = size {
deleteButton.setFrameSize(size)
@ -247,7 +293,7 @@ public extension SKPhotoBrowser {
// MARK: - Public Function For Browser Control
public extension SKPhotoBrowser {
func initializePageIndex(index: Int) {
func initializePageIndex(_ index: Int) {
var i = index
if index >= numberOfPhotos {
i = numberOfPhotos - 1
@ -256,7 +302,7 @@ public extension SKPhotoBrowser {
initialPageIndex = i
currentPageIndex = i
if isViewLoaded() {
if isViewLoaded {
jumpToPageAtIndex(index)
if !isViewActive {
pagingScrollView.tilePages()
@ -264,13 +310,14 @@ public extension SKPhotoBrowser {
}
}
func jumpToPageAtIndex(index: Int) {
func jumpToPageAtIndex(_ index: Int) {
if index < numberOfPhotos {
if !isEndAnimationByToolBar {
return
}
isEndAnimationByToolBar = false
toolbar.updateToolbar(currentPageIndex)
navigationBar.updateNavigationBar(currentPageIndex)
let pageFrame = frameForPageAtIndex(index)
pagingScrollView.animate(pageFrame)
@ -278,7 +325,7 @@ public extension SKPhotoBrowser {
hideControlsAfterDelay()
}
func photoAtIndex(index: Int) -> SKPhotoProtocol {
func photoAtIndex(_ index: Int) -> SKPhotoProtocol {
return photos[index]
}
@ -301,14 +348,14 @@ public extension SKPhotoBrowser {
// reset
cancelControlHiding()
// start
controlVisibilityTimer = NSTimer.scheduledTimerWithTimeInterval(4.0, target: self, selector: #selector(SKPhotoBrowser.hideControls(_:)), userInfo: nil, repeats: false)
controlVisibilityTimer = Timer.scheduledTimer(timeInterval: 4.0, target: self, selector: #selector(SKPhotoBrowser.hideControls(_:)), userInfo: nil, repeats: false)
}
func hideControls() {
setControlsHidden(true, animated: true, permanent: false)
}
func hideControls(timer: NSTimer) {
func hideControls(_ timer: Timer) {
hideControls()
}
@ -320,7 +367,7 @@ public extension SKPhotoBrowser {
return toolbar.alpha == 0.0
}
func popupShare(includeCaption includeCaption: Bool = true) {
func popupShare(includeCaption: Bool = true) {
let photo = photos[currentPageIndex]
guard let underlyingImage = photo.underlyingImage else {
return
@ -329,9 +376,10 @@ public extension SKPhotoBrowser {
var activityItems: [AnyObject] = [underlyingImage]
if photo.caption != nil && includeCaption {
if let shareExtraCaption = SKPhotoBrowserOptions.shareExtraCaption {
activityItems.append(photo.caption + shareExtraCaption)
let caption = photo.caption + shareExtraCaption
activityItems.append(caption as AnyObject)
} else {
activityItems.append(photo.caption)
activityItems.append(photo.caption as AnyObject)
}
}
activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
@ -340,13 +388,13 @@ public extension SKPhotoBrowser {
self.hideControlsAfterDelay()
self.activityViewController = nil
}
if UI_USER_INTERFACE_IDIOM() == .Phone {
presentViewController(activityViewController, animated: true, completion: nil)
if UI_USER_INTERFACE_IDIOM() == .phone {
present(activityViewController, animated: true, completion: nil)
} else {
activityViewController.modalPresentationStyle = .Popover
activityViewController.modalPresentationStyle = .popover
let popover: UIPopoverPresentationController! = activityViewController.popoverPresentationController
popover.barButtonItem = toolbar.toolActionButton
presentViewController(activityViewController, animated: true, completion: nil)
present(activityViewController, animated: true, completion: nil)
}
}
}
@ -366,13 +414,13 @@ internal extension SKPhotoBrowser {
}
}
func pageDisplayedAtIndex(index: Int) -> SKZoomingScrollView? {
func pageDisplayedAtIndex(_ index: Int) -> SKZoomingScrollView? {
return pagingScrollView.pageDisplayedAtIndex(index)
}
func getImageFromView(sender: UIView) -> UIImage {
func getImageFromView(_ sender: UIView) -> UIImage {
UIGraphicsBeginImageContextWithOptions(sender.frame.size, true, 0.0)
sender.layer.renderInContext(UIGraphicsGetCurrentContext()!)
sender.layer.render(in: UIGraphicsGetCurrentContext()!)
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return result!
@ -383,24 +431,16 @@ internal extension SKPhotoBrowser {
internal extension SKPhotoBrowser {
func frameForToolbarAtOrientation() -> CGRect {
let currentOrientation = UIApplication.sharedApplication().statusBarOrientation
var height: CGFloat = navigationController?.navigationBar.frame.size.height ?? 44
if UIInterfaceOrientationIsLandscape(currentOrientation) {
height = 32
}
let height: CGFloat = 44
return CGRect(x: 0, y: view.bounds.size.height - height, width: view.bounds.size.width, height: height)
}
func frameForToolbarHideAtOrientation() -> CGRect {
let currentOrientation = UIApplication.sharedApplication().statusBarOrientation
var height: CGFloat = navigationController?.navigationBar.frame.size.height ?? 44
if UIInterfaceOrientationIsLandscape(currentOrientation) {
height = 32
}
let height: CGFloat = 44
return CGRect(x: 0, y: view.bounds.size.height + height, width: view.bounds.size.width, height: height)
}
func frameForPageAtIndex(index: Int) -> CGRect {
func frameForPageAtIndex(_ index: Int) -> CGRect {
let bounds = pagingScrollView.bounds
var pageFrame = bounds
pageFrame.size.width -= (2 * 10)
@ -412,19 +452,19 @@ internal extension SKPhotoBrowser {
// MARK: - Internal Function For Button Pressed, UIGesture Control
internal extension SKPhotoBrowser {
func panGestureRecognized(sender: UIPanGestureRecognizer) {
func panGestureRecognized(_ sender: UIPanGestureRecognizer) {
guard let zoomingScrollView: SKZoomingScrollView = pagingScrollView.pageDisplayedAtIndex(currentPageIndex) else {
return
}
backgroundView.hidden = true
backgroundView.isHidden = true
let viewHeight: CGFloat = zoomingScrollView.frame.size.height
let viewHalfHeight: CGFloat = viewHeight/2
var translatedPoint: CGPoint = sender.translationInView(self.view)
var translatedPoint: CGPoint = sender.translation(in: self.view)
// gesture began
if sender.state == .Began {
if sender.state == .began {
firstX = zoomingScrollView.center.x
firstY = zoomingScrollView.center.y
@ -440,22 +480,29 @@ internal extension SKPhotoBrowser {
? zoomingScrollView.center.y - viewHalfHeight
: -(zoomingScrollView.center.y - viewHalfHeight)) / viewHalfHeight
view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(max(0.7, offset))
view.alpha = CGFloat.maximum(0.6, offset)
// gesture end
if sender.state == .Ended {
if sender.state == .ended || sender.state == .cancelled || sender.state == .failed {
if zoomingScrollView.center.y > viewHalfHeight + minOffset
|| zoomingScrollView.center.y < viewHalfHeight - minOffset {
backgroundView.backgroundColor = view.backgroundColor
determineAndClose()
if let sender = self.delegate?.viewForPhoto?(self, index: self.currentPageIndex) {
determineAndClose(sender: sender)
} else {
UIView.animate(withDuration: 0.3, animations: {
self.view.alpha = 0
}, completion: { _ in
self.determineAndClose(sender: nil)
})
}
} else {
// Continue Showing View
setNeedsStatusBarAppearanceUpdate()
let velocityY: CGFloat = CGFloat(0.35) * sender.velocityInView(self.view).y
let velocityY: CGFloat = CGFloat(0.35) * sender.velocity(in: self.view).y
let finalX: CGFloat = firstX
let finalY: CGFloat = viewHalfHeight
@ -463,25 +510,26 @@ internal extension SKPhotoBrowser {
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(animationDuration)
UIView.setAnimationCurve(UIViewAnimationCurve.EaseIn)
view.backgroundColor = UIColor.blackColor()
UIView.setAnimationCurve(UIViewAnimationCurve.easeIn)
view.backgroundColor = UIColor.black
view.alpha = 1
zoomingScrollView.center = CGPoint(x: finalX, y: finalY)
UIView.commitAnimations()
}
}
}
func deleteButtonPressed(sender: UIButton) {
func deleteButtonPressed(_ sender: UIButton) {
delegate?.removePhoto?(self, index: currentPageIndex) { [weak self] in
self?.deleteImage()
}
}
func closeButtonPressed(sender: UIButton) {
determineAndClose()
func closeButtonPressed(_ sender: UIButton) {
determineAndClose(sender: nil)
}
func actionButtonPressed(ignoreAndShare ignoreAndShare: Bool) {
func actionButtonPressed(ignoreAndShare: Bool) {
delegate?.willShowActionSheet?(currentPageIndex)
guard numberOfPhotos > 0 else {
@ -489,26 +537,26 @@ internal extension SKPhotoBrowser {
}
if let titles = SKPhotoBrowserOptions.actionButtonTitles {
let actionSheetController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
actionSheetController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: { (action) -> Void in
let actionSheetController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
actionSheetController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { (action) -> Void in
}))
for idx in titles.indices {
actionSheetController.addAction(UIAlertAction(title: titles[idx], style: .Default, handler: { (action) -> Void in
actionSheetController.addAction(UIAlertAction(title: titles[idx], style: .default, handler: { (action) -> Void in
self.delegate?.didDismissActionSheetWithButtonIndex?(idx, photoIndex: self.currentPageIndex)
}))
}
if UI_USER_INTERFACE_IDIOM() == .Phone {
presentViewController(actionSheetController, animated: true, completion: nil)
if UI_USER_INTERFACE_IDIOM() == .phone {
present(actionSheetController, animated: true, completion: nil)
} else {
actionSheetController.modalPresentationStyle = .Popover
actionSheetController.modalPresentationStyle = .popover
if let popoverController = actionSheetController.popoverPresentationController {
popoverController.sourceView = self.view
popoverController.barButtonItem = toolbar.toolActionButton
}
presentViewController(actionSheetController, animated: true, completion: { () -> Void in
present(actionSheetController, animated: true, completion: { () -> Void in
})
}
@ -521,12 +569,12 @@ internal extension SKPhotoBrowser {
// MARK: - Private Function
private extension SKPhotoBrowser {
func configureAppearance() {
view.backgroundColor = .blackColor()
view.backgroundColor = UIColor.black
view.clipsToBounds = true
view.opaque = false
view.isOpaque = false
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: SKMesurement.screenWidth, height: SKMesurement.screenHeight))
backgroundView.backgroundColor = .blackColor()
backgroundView.backgroundColor = UIColor.black
backgroundView.alpha = 0.0
applicationWindow.addSubview(backgroundView)
@ -535,7 +583,6 @@ private extension SKPhotoBrowser {
panGesture = UIPanGestureRecognizer(target: self, action: #selector(SKPhotoBrowser.panGestureRecognized(_:)))
panGesture.minimumNumberOfTouches = 1
panGesture.maximumNumberOfTouches = 1
if !SKPhotoBrowserOptions.disableVerticalSwipe {
view.addGestureRecognizer(panGesture)
}
@ -543,29 +590,40 @@ private extension SKPhotoBrowser {
func configureCloseButton() {
closeButton = SKCloseButton(frame: .zero)
closeButton.addTarget(self, action: #selector(closeButtonPressed(_:)), forControlEvents: .TouchUpInside)
closeButton.hidden = !SKPhotoBrowserOptions.displayCloseButton
closeButton.addTarget(self, action: #selector(closeButtonPressed(_:)), for: .touchUpInside)
closeButton.isHidden = !SKPhotoBrowserOptions.displayCloseButton
view.addSubview(closeButton)
}
func configureDeleteButton() {
deleteButton = SKDeleteButton(frame: .zero)
deleteButton.addTarget(self, action: #selector(deleteButtonPressed(_:)), forControlEvents: .TouchUpInside)
deleteButton.hidden = !SKPhotoBrowserOptions.displayDeleteButton
deleteButton.addTarget(self, action: #selector(deleteButtonPressed(_:)), for: .touchUpInside)
deleteButton.isHidden = !SKPhotoBrowserOptions.displayDeleteButton
view.addSubview(deleteButton)
}
func configureNavigationBar() {
navigationBar = SKNavigationBar(browser: self)
navigationBar.updateFrame(view.bounds.size)
navigationBar.isHidden = !SKPhotoBrowserOptions.displayNavigationBar
navigationBar.onDoneTap = { [weak self] in
self?.willDismissPage?(false)
self?.dismissPhotoBrowser(animated: false)
}
view.addSubview(navigationBar)
}
func configureToolbar() {
toolbar = SKToolbar(frame: frameForToolbarAtOrientation(), browser: self)
view.addSubview(toolbar)
}
func setControlsHidden(hidden: Bool, animated: Bool, permanent: Bool) {
func setControlsHidden(_ hidden: Bool, animated: Bool, permanent: Bool) {
cancelControlHiding()
let captionViews = pagingScrollView.getCaptionViews()
UIView.animateWithDuration(0.35,
UIView.animate(withDuration: 0.35,
animations: { () -> Void in
let alpha: CGFloat = hidden ? 0.0 : 1.0
self.toolbar.alpha = alpha
@ -579,6 +637,10 @@ private extension SKPhotoBrowser {
self.deleteButton.alpha = alpha
self.deleteButton.frame = hidden ? self.deleteButton.hideFrame : self.deleteButton.showFrame
}
if SKPhotoBrowserOptions.displayNavigationBar {
self.navigationBar.alpha = alpha
self.navigationBar.frame = hidden ? self.navigationBar.hideFrame : self.navigationBar.showFrame
}
captionViews.forEach { $0.alpha = alpha }
},
completion: nil)
@ -586,10 +648,11 @@ private extension SKPhotoBrowser {
if !permanent {
hideControlsAfterDelay()
}
setNeedsStatusBarAppearanceUpdate()
}
private func deleteImage() {
func deleteImage() {
defer {
reloadData()
}
@ -597,11 +660,12 @@ private extension SKPhotoBrowser {
if photos.count > 1 {
pagingScrollView.deleteImage()
photos.removeAtIndex(currentPageIndex)
photos.remove(at: currentPageIndex)
if currentPageIndex != 0 {
gotoPreviousPage()
}
toolbar.updateToolbar(currentPageIndex)
navigationBar.updateNavigationBar(currentPageIndex)
} else if photos.count == 1 {
dismissPhotoBrowser(animated: false)
@ -612,7 +676,7 @@ private extension SKPhotoBrowser {
// MARK: - UIScrollView Delegate
extension SKPhotoBrowser: UIScrollViewDelegate {
public func scrollViewDidScroll(scrollView: UIScrollView) {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
guard isViewActive else {
return
}
@ -631,17 +695,18 @@ extension SKPhotoBrowser: UIScrollViewDelegate {
if currentPageIndex != previousCurrentPage {
delegate?.didShowPhotoAtIndex?(currentPageIndex)
toolbar.updateToolbar(currentPageIndex)
navigationBar.updateNavigationBar(currentPageIndex)
}
}
public func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
hideControlsAfterDelay()
let currentIndex = pagingScrollView.contentOffset.x / pagingScrollView.frame.size.width
delegate?.didScrollToIndex?(Int(currentIndex))
}
public func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
isEndAnimationByToolBar = true
}
}

View File

@ -15,28 +15,28 @@ import Foundation
- Parameter index: the index of the new photo
*/
optional func didShowPhotoAtIndex(index: Int)
@objc optional func didShowPhotoAtIndex(_ index: Int)
/**
Tells the delegate the browser will start to dismiss
- Parameter index: the index of the current photo
*/
optional func willDismissAtPageIndex(index: Int)
@objc optional func willDismissAtPageIndex(_ index: Int)
/**
Tells the delegate that the browser will start showing the `UIActionSheet`
- Parameter photoIndex: the index of the current photo
*/
optional func willShowActionSheet(photoIndex: Int)
@objc optional func willShowActionSheet(_ photoIndex: Int)
/**
Tells the delegate that the browser has been dismissed
- Parameter index: the index of the current photo
*/
optional func didDismissAtPageIndex(index: Int)
@objc optional func didDismissAtPageIndex(_ index: Int)
/**
Tells the delegate that the browser did dismiss the UIActionSheet
@ -44,14 +44,14 @@ import Foundation
- Parameter buttonIndex: the index of the pressed button
- Parameter photoIndex: the index of the current photo
*/
optional func didDismissActionSheetWithButtonIndex(buttonIndex: Int, photoIndex: Int)
@objc optional func didDismissActionSheetWithButtonIndex(_ buttonIndex: Int, photoIndex: Int)
/**
Tells the delegate that the browser did scroll to index
- Parameter index: the index of the photo where the user had scroll
*/
optional func didScrollToIndex(index: Int)
@objc optional func didScrollToIndex(_ index: Int)
/**
Tells the delegate the user removed a photo, when implementing this call, be sure to call reload to finish the deletion process
@ -60,7 +60,7 @@ import Foundation
- Parameter index: the index of the removed photo
- Parameter reload: function that needs to be called after finishing syncing up
*/
optional func removePhoto(browser: SKPhotoBrowser, index: Int, reload: (() -> Void))
@objc optional func removePhoto(_ browser: SKPhotoBrowser, index: Int, reload: (() -> Void))
/**
Asks the delegate for the view for a certain photo. Needed to detemine the animation when presenting/closing the browser.
@ -70,6 +70,6 @@ import Foundation
- Returns: the view to animate to
*/
optional func viewForPhoto(browser: SKPhotoBrowser, index: Int) -> UIView?
@objc optional func viewForPhoto(_ browser: SKPhotoBrowser, index: Int) -> UIView?
}

View File

@ -18,10 +18,16 @@ public struct SKPhotoBrowserOptions {
public static var displayBackAndForwardButton: Bool = true
public static var disableVerticalSwipe: Bool = false
public static var displayCloseButton = true
public static var displayCloseButton = false
public static var displayNavigationBar = true
public static var displayDeleteButton = false
public static var navigationBarCounterSepatator = "из"
public static var navigationBarDoneTitle = "Готово"
public static var bounceAnimation = false
public static var enableZoomBlackArea = true
public static var enableSingleTapDismiss = false
}
public static var imageLoadingCustomHeaders: [String : String]?
}

View File

@ -9,7 +9,7 @@
import Foundation
// helpers which often used
private let bundle = NSBundle(forClass: SKPhotoBrowser.self)
private let bundle = Bundle(for: SKPhotoBrowser.self)
class SKToolbar: UIToolbar {
var toolCounterLabel: UILabel!
@ -18,7 +18,7 @@ class SKToolbar: UIToolbar {
var toolNextButton: UIBarButtonItem!
var toolActionButton: UIBarButtonItem!
private weak var browser: SKPhotoBrowser?
fileprivate weak var browser: SKPhotoBrowser?
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
@ -40,7 +40,7 @@ class SKToolbar: UIToolbar {
setupToolbar()
}
func updateToolbar(currentPageIndex: Int) {
func updateToolbar(_ currentPageIndex: Int) {
guard let browser = browser else { return }
if browser.numberOfPhotos > 1 {
@ -49,28 +49,28 @@ class SKToolbar: UIToolbar {
toolCounterLabel.text = nil
}
toolPreviousButton.enabled = (currentPageIndex > 0)
toolNextButton.enabled = (currentPageIndex < browser.numberOfPhotos - 1)
toolPreviousButton.isEnabled = (currentPageIndex > 0)
toolNextButton.isEnabled = (currentPageIndex < browser.numberOfPhotos - 1)
}
}
private extension SKToolbar {
func setupApperance() {
backgroundColor = .clearColor()
backgroundColor = UIColor.black.withAlphaComponent(0.65)
clipsToBounds = true
translucent = true
setBackgroundImage(UIImage(), forToolbarPosition: .Any, barMetrics: .Default)
isTranslucent = true
setBackgroundImage(UIImage(), forToolbarPosition: .any, barMetrics: .default)
// toolbar
if !SKPhotoBrowserOptions.displayToolbar {
hidden = true
isHidden = true
}
}
func setupToolbar() {
guard let browser = browser else { return }
let flexSpace = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: self, action: nil)
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
var items = [UIBarButtonItem]()
items.append(flexSpace)
if browser.numberOfPhotos > 1 && SKPhotoBrowserOptions.displayBackAndForwardButton {
@ -95,30 +95,30 @@ private extension SKToolbar {
func setupPreviousButton() {
let previousBtn = SKPreviousButton(frame: frame)
previousBtn.addTarget(browser, action: #selector(SKPhotoBrowser.gotoPreviousPage), forControlEvents: .TouchUpInside)
previousBtn.addTarget(browser, action: #selector(SKPhotoBrowser.gotoPreviousPage), for: .touchUpInside)
toolPreviousButton = UIBarButtonItem(customView: previousBtn)
}
func setupNextButton() {
let nextBtn = SKNextButton(frame: frame)
nextBtn.addTarget(browser, action: #selector(SKPhotoBrowser.gotoNextPage), forControlEvents: .TouchUpInside)
nextBtn.addTarget(browser, action: #selector(SKPhotoBrowser.gotoNextPage), for: .touchUpInside)
toolNextButton = UIBarButtonItem(customView: nextBtn)
}
func setupCounterLabel() {
toolCounterLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 95, height: 40))
toolCounterLabel.textAlignment = .Center
toolCounterLabel.backgroundColor = .clearColor()
toolCounterLabel.textAlignment = .center
toolCounterLabel.backgroundColor = UIColor.clear
toolCounterLabel.font = UIFont(name: "Helvetica", size: 16.0)
toolCounterLabel.textColor = .whiteColor()
toolCounterLabel.shadowColor = .darkTextColor()
toolCounterLabel.textColor = UIColor.white
toolCounterLabel.shadowColor = UIColor.black
toolCounterLabel.shadowOffset = CGSize(width: 0.0, height: 1.0)
toolCounterButton = UIBarButtonItem(customView: toolCounterLabel)
}
func setupActionButton() {
toolActionButton = UIBarButtonItem(barButtonSystemItem: .Action, target: browser, action: #selector(SKPhotoBrowser.actionButtonPressed))
toolActionButton.tintColor = .whiteColor()
toolActionButton = UIBarButtonItem(barButtonSystemItem: .action, target: browser, action: #selector(SKPhotoBrowser.actionButtonPressed))
toolActionButton.tintColor = UIColor.white
}
}
@ -126,16 +126,16 @@ private extension SKToolbar {
class SKToolbarButton: UIButton {
let insets: UIEdgeInsets = UIEdgeInsets(top: 13.25, left: 17.25, bottom: 13.25, right: 17.25)
func setup(imageName: String) {
backgroundColor = .clearColor()
func setup(_ imageName: String) {
backgroundColor = UIColor.clear
imageEdgeInsets = insets
translatesAutoresizingMaskIntoConstraints = true
autoresizingMask = [.FlexibleBottomMargin, .FlexibleLeftMargin, .FlexibleRightMargin, .FlexibleTopMargin]
contentMode = .Center
autoresizingMask = [.flexibleBottomMargin, .flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin]
contentMode = .center
let image = UIImage(named: "SKPhotoBrowser.bundle/images/\(imageName)",
inBundle: bundle, compatibleWithTraitCollection: nil) ?? UIImage()
setImage(image, forState: .Normal)
in: bundle, compatibleWith: nil) ?? UIImage()
setImage(image, for: UIControlState())
}
}
@ -161,4 +161,4 @@ class SKNextButton: SKToolbarButton {
super.init(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
setup(imageName)
}
}
}

View File

@ -8,7 +8,7 @@
import UIKit
public class SKZoomingScrollView: UIScrollView {
open class SKZoomingScrollView: UIScrollView {
var captionView: SKCaptionView!
var photo: SKPhotoProtocol! {
didSet {
@ -19,10 +19,10 @@ public class SKZoomingScrollView: UIScrollView {
}
}
private(set) var photoImageView: SKDetectingImageView!
private weak var photoBrowser: SKPhotoBrowser?
private var tapView: SKDetectingView!
private var indicatorView: SKIndicatorView!
fileprivate(set) var photoImageView: SKDetectingImageView!
fileprivate weak var photoBrowser: SKPhotoBrowser?
fileprivate var tapView: SKDetectingView!
fileprivate var indicatorView: SKIndicatorView!
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
@ -48,15 +48,15 @@ public class SKZoomingScrollView: UIScrollView {
// tap
tapView = SKDetectingView(frame: bounds)
tapView.delegate = self
tapView.backgroundColor = UIColor.clearColor()
tapView.autoresizingMask = [.FlexibleHeight, .FlexibleWidth]
tapView.backgroundColor = UIColor.clear
tapView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
addSubview(tapView)
// image
photoImageView = SKDetectingImageView(frame: frame)
photoImageView.delegate = self
photoImageView.contentMode = .Bottom
photoImageView.backgroundColor = .clearColor()
photoImageView.contentMode = .bottom
photoImageView.backgroundColor = UIColor.clear
addSubview(photoImageView)
// indicator
@ -64,17 +64,17 @@ public class SKZoomingScrollView: UIScrollView {
addSubview(indicatorView)
// self
backgroundColor = .clearColor()
backgroundColor = UIColor.clear
delegate = self
showsHorizontalScrollIndicator = false
showsVerticalScrollIndicator = false
decelerationRate = UIScrollViewDecelerationRateFast
autoresizingMask = [.FlexibleWidth, .FlexibleTopMargin, .FlexibleBottomMargin, .FlexibleRightMargin, .FlexibleLeftMargin]
autoresizingMask = [.flexibleWidth, .flexibleTopMargin, .flexibleBottomMargin, .flexibleRightMargin, .flexibleLeftMargin]
}
// MARK: - override
public override func layoutSubviews() {
open override func layoutSubviews() {
tapView.frame = bounds
indicatorView.frame = bounds
@ -97,12 +97,12 @@ public class SKZoomingScrollView: UIScrollView {
}
// Center
if !CGRectEqualToRect(photoImageView.frame, frameToCenter) {
if !photoImageView.frame.equalTo(frameToCenter) {
photoImageView.frame = frameToCenter
}
}
public func setMaxMinZoomScalesForCurrentBounds() {
open func setMaxMinZoomScalesForCurrentBounds() {
maximumZoomScale = 1
minimumZoomScale = 1
zoomScale = 1
@ -114,18 +114,18 @@ public class SKZoomingScrollView: UIScrollView {
let boundsSize = bounds.size
let imageSize = photoImageView.frame.size
let xScale = boundsSize.width / imageSize.width
let yScale = boundsSize.height / imageSize.height
let xScale = CGFloat(Int(boundsSize.width / imageSize.width * 100)) / 100
let yScale = CGFloat(Int(boundsSize.height / imageSize.height * 100)) / 100
let minScale: CGFloat = min(xScale, yScale)
var maxScale: CGFloat = 1.0
let scale = max(UIScreen.mainScreen().scale, 2.0)
let deviceScreenWidth = UIScreen.mainScreen().bounds.width * scale // width in pixels. scale needs to remove if to use the old algorithm
let deviceScreenHeight = UIScreen.mainScreen().bounds.height * scale // height in pixels. scale needs to remove if to use the old algorithm
let scale = max(UIScreen.main.scale, 2.0)
let deviceScreenWidth = UIScreen.main.bounds.width * scale // width in pixels. scale needs to remove if to use the old algorithm
let deviceScreenHeight = UIScreen.main.bounds.height * scale // height in pixels. scale needs to remove if to use the old algorithm
if photoImageView.frame.width < deviceScreenWidth {
// I think that we should to get coefficient between device screen width and image width and assign it to maxScale. I made two mode that we will get the same result for different device orientations.
if UIApplication.sharedApplication().statusBarOrientation.isPortrait {
if UIApplication.shared.statusBarOrientation.isPortrait {
maxScale = deviceScreenHeight / photoImageView.frame.width
} else {
maxScale = deviceScreenWidth / photoImageView.frame.width
@ -156,7 +156,7 @@ public class SKZoomingScrollView: UIScrollView {
setNeedsLayout()
}
public func prepareForReuse() {
open func prepareForReuse() {
photo = nil
if captionView != nil {
captionView.removeFromSuperview()
@ -165,7 +165,7 @@ public class SKZoomingScrollView: UIScrollView {
}
// MARK: - image
public func displayImage(complete flag: Bool) {
open func displayImage(complete flag: Bool) {
// reset scale
maximumZoomScale = 1
minimumZoomScale = 1
@ -200,14 +200,14 @@ public class SKZoomingScrollView: UIScrollView {
setNeedsLayout()
}
public func displayImageFailure() {
open func displayImageFailure() {
indicatorView.stopAnimating()
}
// MARK: - handle tap
public func handleDoubleTap(touchPoint: CGPoint) {
open func handleDoubleTap(_ touchPoint: CGPoint) {
if let photoBrowser = photoBrowser {
NSObject.cancelPreviousPerformRequestsWithTarget(photoBrowser)
NSObject.cancelPreviousPerformRequests(withTarget: photoBrowser)
}
if zoomScale > minimumZoomScale {
@ -222,7 +222,7 @@ public class SKZoomingScrollView: UIScrollView {
}
*/
let zoomRect = zoomRectForScrollViewWith(maximumZoomScale, touchPoint: touchPoint)
zoomToRect(zoomRect, animated: true)
zoom(to: zoomRect, animated: true)
}
// delay control
@ -233,15 +233,15 @@ public class SKZoomingScrollView: UIScrollView {
// MARK: - UIScrollViewDelegate
extension SKZoomingScrollView: UIScrollViewDelegate {
public func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
public func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return photoImageView
}
public func scrollViewWillBeginZooming(scrollView: UIScrollView, withView view: UIView?) {
public func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
photoBrowser?.cancelControlHiding()
}
public func scrollViewDidZoom(scrollView: UIScrollView) {
public func scrollViewDidZoom(_ scrollView: UIScrollView) {
setNeedsLayout()
layoutIfNeeded()
}
@ -250,7 +250,7 @@ extension SKZoomingScrollView: UIScrollViewDelegate {
// MARK: - SKDetectingImageViewDelegate
extension SKZoomingScrollView: SKDetectingViewDelegate {
func handleSingleTap(view: UIView, touch: UITouch) {
func handleSingleTap(_ view: UIView, touch: UITouch) {
guard let browser = photoBrowser else {
return
}
@ -259,13 +259,13 @@ extension SKZoomingScrollView: SKDetectingViewDelegate {
}
if browser.areControlsHidden() == false && SKPhotoBrowserOptions.enableSingleTapDismiss == true {
browser.determineAndClose()
browser.determineAndClose(sender: nil)
} else {
browser.toggleControls()
}
}
func handleDoubleTap(view: UIView, touch: UITouch) {
func handleDoubleTap(_ view: UIView, touch: UITouch) {
if SKPhotoBrowserOptions.enableZoomBlackArea == true {
let needPoint = getViewFramePercent(view, touch: touch)
handleDoubleTap(needPoint)
@ -277,26 +277,26 @@ extension SKZoomingScrollView: SKDetectingViewDelegate {
// MARK: - SKDetectingImageViewDelegate
extension SKZoomingScrollView: SKDetectingImageViewDelegate {
func handleImageViewSingleTap(touchPoint: CGPoint) {
func handleImageViewSingleTap(_ touchPoint: CGPoint) {
guard let browser = photoBrowser else {
return
}
if SKPhotoBrowserOptions.enableSingleTapDismiss {
browser.determineAndClose()
browser.determineAndClose(sender: nil)
} else {
browser.toggleControls()
}
}
func handleImageViewDoubleTap(touchPoint: CGPoint) {
func handleImageViewDoubleTap(_ touchPoint: CGPoint) {
handleDoubleTap(touchPoint)
}
}
private extension SKZoomingScrollView {
func getViewFramePercent(view: UIView, touch: UITouch) -> CGPoint {
func getViewFramePercent(_ view: UIView, touch: UITouch) -> CGPoint {
let oneWidthViewPercent = view.bounds.width / 100
let viewTouchPoint = touch.locationInView(view)
let viewTouchPoint = touch.location(in: view)
let viewWidthTouch = viewTouchPoint.x
let viewPercentTouch = viewWidthTouch / oneWidthViewPercent
@ -315,12 +315,12 @@ private extension SKZoomingScrollView {
return allPoint
}
func zoomRectForScrollViewWith(scale: CGFloat, touchPoint: CGPoint) -> CGRect {
func zoomRectForScrollViewWith(_ scale: CGFloat, touchPoint: CGPoint) -> CGRect {
let w = frame.size.width / scale
let h = frame.size.height / scale
let x = touchPoint.x - (h / max(UIScreen.mainScreen().scale, 2.0))
let y = touchPoint.y - (w / max(UIScreen.mainScreen().scale, 2.0))
let x = touchPoint.x - (h / max(UIScreen.main.scale, 2.0))
let y = touchPoint.y - (w / max(UIScreen.main.scale, 2.0))
return CGRect(x: x, y: y, width: w, height: h)
}
}
}

View File

@ -11,7 +11,7 @@ import UIKit
extension UIImage {
func rotateImageByOrientation() -> UIImage {
// No-op if the orientation is already correct
guard self.imageOrientation != .Up else {
guard self.imageOrientation != .up else {
return self
}
@ -19,58 +19,58 @@ extension UIImage {
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
let ctx = CGBitmapContextCreate(nil, Int(self.size.width), Int(self.size.height),
CGImageGetBitsPerComponent(self.CGImage!), 0,
CGImageGetColorSpace(self.CGImage!)!,
CGImageGetBitmapInfo(self.CGImage!).rawValue)
CGContextConcatCTM(ctx!, transform)
let ctx = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height),
bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0,
space: self.cgImage!.colorSpace!,
bitmapInfo: self.cgImage!.bitmapInfo.rawValue)
ctx!.concatenate(transform)
switch self.imageOrientation {
case .Left, .LeftMirrored, .Right, .RightMirrored:
CGContextDrawImage(ctx!, CGRect(x: 0, y: 0, width: size.height, height: size.width), self.CGImage!)
case .left, .leftMirrored, .right, .rightMirrored:
ctx!.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
default:
CGContextDrawImage(ctx!, CGRect(x: 0, y: 0, width: size.width, height: size.height), self.CGImage!)
ctx!.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
}
// And now we just create a new UIImage from the drawing context
if let cgImage = CGBitmapContextCreateImage(ctx!) {
return UIImage(CGImage: cgImage)
if let cgImage = ctx!.makeImage() {
return UIImage(cgImage: cgImage)
} else {
return self
}
}
private func calculateAffineTransform() -> CGAffineTransform {
fileprivate func calculateAffineTransform() -> CGAffineTransform {
// We need to calculate the proper transformation to make the image upright.
// We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
var transform = CGAffineTransformIdentity
var transform = CGAffineTransform.identity
switch self.imageOrientation {
case .Down, .DownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
case .down, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: self.size.height)
transform = transform.rotated(by: CGFloat(M_PI))
case .Left, .LeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
case .left, .leftMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.rotated(by: CGFloat(M_PI_2))
case .Right, .RightMirrored:
transform = CGAffineTransformTranslate(transform, 0, self.size.height)
transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
case .right, .rightMirrored:
transform = transform.translatedBy(x: 0, y: self.size.height)
transform = transform.rotated(by: CGFloat(-M_PI_2))
default:
break
}
switch self.imageOrientation {
case .UpMirrored, .DownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0)
transform = CGAffineTransformScale(transform, -1, 1)
case .upMirrored, .downMirrored:
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
case .LeftMirrored, .RightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.height, 0)
transform = CGAffineTransformScale(transform, -1, 1)
case .leftMirrored, .rightMirrored:
transform = transform.translatedBy(x: self.size.height, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
default:
break

View File

@ -9,13 +9,13 @@
import UIKit
extension UIView {
func addCornerRadiusAnimation(from: CGFloat, to: CGFloat, duration: CFTimeInterval) {
func addCornerRadiusAnimation(_ from: CGFloat, to: CGFloat, duration: CFTimeInterval) {
let animation = CABasicAnimation(keyPath: "cornerRadius")
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
animation.fromValue = from
animation.toValue = to
animation.duration = duration
self.layer.addAnimation(animation, forKey: "cornerRadius")
self.layer.add(animation, forKey: "cornerRadius")
self.layer.cornerRadius = to
}
}

View File

@ -1,5 +1,6 @@
platform :ios, '8.0'
platform :ios, '9.0'
use_frameworks!
pod 'SDWebImage', '~>3.8'
target "SKPhotoBrowserExample" do
pod 'SDWebImage', '~>3.8'
end

View File

@ -9,4 +9,6 @@ DEPENDENCIES:
SPEC CHECKSUMS:
SDWebImage: 35f9627a3e44b4f292a8a8ce6a531fa488239b91
COCOAPODS: 0.39.0
PODFILE CHECKSUM: a32274f1ce260fbc242dfd48f2b1af8a84a5bc0e
COCOAPODS: 1.1.0.beta.2

View File

@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
212705891C92C69C00466223 /* FromCameraRollViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 212705881C92C69C00466223 /* FromCameraRollViewController.swift */; };
88ABF7F872EE84010BCE3BD6 /* Pods_SKPhotoBrowserExample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB686E31A24C3FFC5B05ECF8 /* Pods_SKPhotoBrowserExample.framework */; };
8909B55B1BC792150060A053 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8909B55A1BC792150060A053 /* AppDelegate.swift */; };
8909B55D1BC792150060A053 /* FromLocalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8909B55C1BC792150060A053 /* FromLocalViewController.swift */; };
8909B5601BC792150060A053 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8909B55E1BC792150060A053 /* Main.storyboard */; };
@ -28,7 +29,6 @@
89FC5DBB1D54A04900F1BE52 /* FromWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89FC5DBA1D54A04900F1BE52 /* FromWebViewController.swift */; };
A6A7B7801C9578E30025AC07 /* SKPhotoBrowser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8909B5711BC792570060A053 /* SKPhotoBrowser.framework */; };
A6A7B7811C9578E30025AC07 /* SKPhotoBrowser.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8909B5711BC792570060A053 /* SKPhotoBrowser.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
DDFD24AF2FBA5A60984D378D /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7C2188E912BB106233AA4AB2 /* Pods.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -71,6 +71,8 @@
/* Begin PBXFileReference section */
212705881C92C69C00466223 /* FromCameraRollViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FromCameraRollViewController.swift; sourceTree = "<group>"; };
241888FD69B198BD34C3C0BB /* Pods-SKPhotoBrowserExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SKPhotoBrowserExample.release.xcconfig"; path = "Pods/Target Support Files/Pods-SKPhotoBrowserExample/Pods-SKPhotoBrowserExample.release.xcconfig"; sourceTree = "<group>"; };
4646E40B4CEC62B4734AB729 /* Pods-SKPhotoBrowserExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SKPhotoBrowserExample.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SKPhotoBrowserExample/Pods-SKPhotoBrowserExample.debug.xcconfig"; sourceTree = "<group>"; };
7C2188E912BB106233AA4AB2 /* Pods.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8909B5571BC792150060A053 /* SKPhotoBrowserExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SKPhotoBrowserExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
8909B55A1BC792150060A053 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@ -93,8 +95,7 @@
8909B57F1BC792DC0060A053 /* image8.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image8.jpg; sourceTree = "<group>"; };
8909B5801BC792DC0060A053 /* image9.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image9.jpg; sourceTree = "<group>"; };
89FC5DBA1D54A04900F1BE52 /* FromWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FromWebViewController.swift; sourceTree = "<group>"; };
B3E081D4F2C8623852C459F5 /* 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>"; };
DD077DBD0C164C96BCC7494F /* 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>"; };
BB686E31A24C3FFC5B05ECF8 /* Pods_SKPhotoBrowserExample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SKPhotoBrowserExample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -103,21 +104,30 @@
buildActionMask = 2147483647;
files = (
A6A7B7801C9578E30025AC07 /* SKPhotoBrowser.framework in Frameworks */,
DDFD24AF2FBA5A60984D378D /* Pods.framework in Frameworks */,
88ABF7F872EE84010BCE3BD6 /* Pods_SKPhotoBrowserExample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
4462E0EB8EBBBA6309EEEEB9 /* Pods */ = {
isa = PBXGroup;
children = (
4646E40B4CEC62B4734AB729 /* Pods-SKPhotoBrowserExample.debug.xcconfig */,
241888FD69B198BD34C3C0BB /* Pods-SKPhotoBrowserExample.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
8909B54E1BC792150060A053 = {
isa = PBXGroup;
children = (
8909B56C1BC792570060A053 /* SKPhotoBrowser.xcodeproj */,
8909B5591BC792150060A053 /* SKPhotoBrowserExample */,
8909B5581BC792150060A053 /* Products */,
D1D8ECD45B290372235B8168 /* Pods */,
C646D2C27A5B9CCC003A9BD1 /* Frameworks */,
4462E0EB8EBBBA6309EEEEB9 /* Pods */,
);
sourceTree = "<group>";
};
@ -209,19 +219,11 @@
isa = PBXGroup;
children = (
7C2188E912BB106233AA4AB2 /* Pods.framework */,
BB686E31A24C3FFC5B05ECF8 /* Pods_SKPhotoBrowserExample.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
D1D8ECD45B290372235B8168 /* Pods */ = {
isa = PBXGroup;
children = (
B3E081D4F2C8623852C459F5 /* Pods.debug.xcconfig */,
DD077DBD0C164C96BCC7494F /* Pods.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -229,13 +231,13 @@
isa = PBXNativeTarget;
buildConfigurationList = 8909B5691BC792150060A053 /* Build configuration list for PBXNativeTarget "SKPhotoBrowserExample" */;
buildPhases = (
F19A62C34B2F0CFF753F30C3 /* Check Pods Manifest.lock */,
E821EE59F7DDA23D9BBBB509 /* [CP] Check Pods Manifest.lock */,
8909B5531BC792150060A053 /* Sources */,
8909B5541BC792150060A053 /* Frameworks */,
8909B5551BC792150060A053 /* Resources */,
A6A7B7841C9578E30025AC07 /* Embed Frameworks */,
575DBD5855AB711E5773767A /* Embed Pods Frameworks */,
2ECF43C4E99CDE3D98AE6842 /* Copy Pods Resources */,
B9953EC3B1AD6BDFDD63D74C /* [CP] Embed Pods Frameworks */,
554ADE9B9A609F47590589FC /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -253,7 +255,7 @@
8909B54F1BC792150060A053 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
LastUpgradeCheck = 0800;
ORGANIZATIONNAME = suzuki_keishi;
TargetAttributes = {
8909B5561BC792150060A053 = {
@ -329,49 +331,49 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
2ECF43C4E99CDE3D98AE6842 /* Copy Pods Resources */ = {
554ADE9B9A609F47590589FC /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Copy Pods Resources";
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SKPhotoBrowserExample/Pods-SKPhotoBrowserExample-resources.sh\"\n";
showEnvVarsInLog = 0;
};
575DBD5855AB711E5773767A /* Embed Pods Frameworks */ = {
B9953EC3B1AD6BDFDD63D74C /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Embed Pods Frameworks";
name = "[CP] Embed Pods Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n";
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SKPhotoBrowserExample/Pods-SKPhotoBrowserExample-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
F19A62C34B2F0CFF753F30C3 /* Check Pods Manifest.lock */ = {
E821EE59F7DDA23D9BBBB509 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Check Pods Manifest.lock";
name = "[CP] 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";
shellScript = "diff \"${PODS_ROOT}/../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";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@ -431,8 +433,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";
@ -476,8 +480,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";
@ -496,6 +502,7 @@
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
@ -503,31 +510,31 @@
};
8909B56A1BC792150060A053 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B3E081D4F2C8623852C459F5 /* Pods.debug.xcconfig */;
baseConfigurationReference = 4646E40B4CEC62B4734AB729 /* Pods-SKPhotoBrowserExample.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
INFOPLIST_FILE = SKPhotoBrowserExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.keishi.suzuki.aSKPhotoBrowserExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
};
name = Debug;
};
8909B56B1BC792150060A053 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = DD077DBD0C164C96BCC7494F /* Pods.release.xcconfig */;
baseConfigurationReference = 241888FD69B198BD34C3C0BB /* Pods-SKPhotoBrowserExample.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
INFOPLIST_FILE = SKPhotoBrowserExample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.keishi.suzuki.aSKPhotoBrowserExample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 2.3;
SWIFT_VERSION = 3.0;
};
name = Release;
};

View File

@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(application: UIApplication) {
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
func applicationDidEnterBackground(application: UIApplication) {
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(application: UIApplication) {
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(application: UIApplication) {
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(application: UIApplication) {
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

View File

@ -14,22 +14,22 @@ class FromCameraRollViewController: UIViewController, SKPhotoBrowserDelegate, UI
@IBOutlet weak var collectionView: UICollectionView!
private let imageManager = PHCachingImageManager.defaultManager()
fileprivate let imageManager = PHCachingImageManager.default()
private var assets: [PHAsset] = []
fileprivate var assets: [PHAsset] = []
private lazy var requestOptions: PHImageRequestOptions = {
fileprivate lazy var requestOptions: PHImageRequestOptions = {
let options = PHImageRequestOptions()
options.deliveryMode = .Opportunistic
options.resizeMode = .Fast
options.deliveryMode = .opportunistic
options.resizeMode = .fast
return options
}()
private lazy var bigRequestOptions: PHImageRequestOptions = {
fileprivate lazy var bigRequestOptions: PHImageRequestOptions = {
let options = PHImageRequestOptions()
options.deliveryMode = .HighQualityFormat
options.resizeMode = .Fast
options.deliveryMode = .highQualityFormat
options.resizeMode = .fast
return options
}()
@ -58,21 +58,21 @@ class FromCameraRollViewController: UIViewController, SKPhotoBrowserDelegate, UI
// MARK: UICollectionViewDataSource
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
func numberOfSections(in collectionView: UICollectionView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return assets.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("exampleCollectionViewCell", forIndexPath: indexPath)
let asset = assets[indexPath.row]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "exampleCollectionViewCell", for: indexPath)
let asset = assets[(indexPath as NSIndexPath).row]
if let cell = cell as? AssetExampleCollectionViewCell {
if let id = cell.requestId {
@ -91,16 +91,16 @@ class FromCameraRollViewController: UIViewController, SKPhotoBrowserDelegate, UI
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItemAtIndexPath(indexPath) as? ExampleCollectionViewCell else {
guard let cell = collectionView.cellForItem(at: indexPath) as? ExampleCollectionViewCell else {
return
}
guard let originImage = cell.exampleImageView.image else {
return
}
func open(images: [UIImage]) {
func open(_ images: [UIImage]) {
let photoImages: [SKPhotoProtocol] = images.map({ return SKPhoto.photoWithImage($0) })
let browser = SKPhotoBrowser(originImage: cell.exampleImageView.image!, photos: photoImages, animatedFromView: cell)
@ -110,17 +110,17 @@ class FromCameraRollViewController: UIViewController, SKPhotoBrowserDelegate, UI
// browser.bounceAnimation = true
// browser.displayDeleteButton = true
// browser.displayAction = false
self.presentViewController(browser, animated: true, completion: {})
self.present(browser, animated: true, completion: {})
}
var fetchedImages: [UIImage] = Array<UIImage>(count: assets.count, repeatedValue: UIImage())
var fetchedImages: [UIImage] = Array<UIImage>(repeating: UIImage(), count: assets.count)
var fetched = 0
assets.forEach { (asset) -> () in
requestImageForAsset(asset, options:bigRequestOptions, completion: { [weak self] (image, requestId) -> () in
_ = requestImageForAsset(asset, options:bigRequestOptions, completion: { [weak self] (image, requestId) -> () in
if let image = image, index = self?.assets.indexOf(asset) {
if let image = image, let index = self?.assets.index(of: asset) {
fetchedImages[index] = image
}
fetched += 1
@ -132,55 +132,55 @@ class FromCameraRollViewController: UIViewController, SKPhotoBrowserDelegate, UI
}
}
private func fetchAssets() {
fileprivate func fetchAssets() {
let options = PHFetchOptions()
let limit = 8
options.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.Image.rawValue)
options.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue)
options.fetchLimit = limit
let result = PHAsset.fetchAssetsWithOptions(options)
let result = PHAsset.fetchAssets(with: options)
let amount = min(result.count, limit)
self.assets = result.objectsAtIndexes(NSIndexSet(indexesInRange: NSRange(location: 0, length: amount))) as? [PHAsset] ?? []
self.assets = result.objects(at: IndexSet(integersIn: NSRange(location: 0, length: amount).toRange() ?? 0..<0))
}
private func requestImageForAsset(asset: PHAsset, options: PHImageRequestOptions, completion: (image: UIImage?, requestId: PHImageRequestID?) -> ()) -> PHImageRequestID {
fileprivate func requestImageForAsset(_ asset: PHAsset, options: PHImageRequestOptions, completion: @escaping (_ image: UIImage?, _ requestId: PHImageRequestID?) -> ()) -> PHImageRequestID {
let scale = UIScreen.mainScreen().scale
let scale = UIScreen.main.scale
let targetSize: CGSize
if options.deliveryMode == .HighQualityFormat {
if options.deliveryMode == .highQualityFormat {
targetSize = CGSize(width: 600 * scale, height: 600 * scale)
} else {
targetSize = CGSize(width: 182 * scale, height: 182 * scale)
}
requestOptions.synchronous = false
requestOptions.isSynchronous = false
// Workaround because PHImageManager.requestImageForAsset doesn't work for burst images
if asset.representsBurst {
return imageManager.requestImageDataForAsset(asset, options: options) { data, _, _, dict in
return imageManager.requestImageData(for: asset, options: options) { data, _, _, dict in
let image = data.flatMap { UIImage(data: $0) }
let requestId = dict?[PHImageResultRequestIDKey] as? NSNumber
completion(image: image, requestId: requestId?.intValue)
completion(image, requestId?.int32Value)
}
} else {
return imageManager.requestImageForAsset(asset, targetSize: targetSize, contentMode: .AspectFill, options: options) { image, dict in
return imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { image, dict in
let requestId = dict?[PHImageResultRequestIDKey] as? NSNumber
completion(image: image, requestId: requestId?.intValue)
completion(image, requestId?.int32Value)
}
}
}
override func prefersStatusBarHidden() -> Bool {
override var prefersStatusBarHidden: Bool {
return false
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}

View File

@ -25,28 +25,28 @@ class FromLocalViewController: UIViewController, UICollectionViewDataSource, UIC
super.didReceiveMemoryWarning()
}
override func prefersStatusBarHidden() -> Bool {
override var prefersStatusBarHidden: Bool {
return false
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}
// MARK: - UICollectionViewDataSource
extension FromLocalViewController {
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return images.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCellWithReuseIdentifier("exampleCollectionViewCell", forIndexPath: indexPath) as? ExampleCollectionViewCell else {
@objc(collectionView:cellForItemAtIndexPath:) func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "exampleCollectionViewCell", for: indexPath) as? ExampleCollectionViewCell else {
return UICollectionViewCell()
}
cell.exampleImageView.image = UIImage(named: "image\(indexPath.row % 10).jpg")
cell.exampleImageView.image = UIImage(named: "image\((indexPath as NSIndexPath).row % 10).jpg")
// cell.exampleImageView.contentMode = .ScaleAspectFill
return cell
}
@ -55,8 +55,8 @@ extension FromLocalViewController {
// MARK: - UICollectionViewDelegate
extension FromLocalViewController {
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
guard let cell = collectionView.cellForItemAtIndexPath(indexPath) as? ExampleCollectionViewCell else {
@objc(collectionView:didSelectItemAtIndexPath:) func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? ExampleCollectionViewCell else {
return
}
guard let originImage = cell.exampleImageView.image else {
@ -70,14 +70,14 @@ extension FromLocalViewController {
browser.delegate = self
// browser.updateCloseButton(UIImage(named: "image1.jpg")!)
presentViewController(browser, animated: true, completion: {})
present(browser, animated: true, completion: {})
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
if UIDevice.currentDevice().userInterfaceIdiom == .Pad {
return CGSize(width: UIScreen.mainScreen().bounds.size.width / 2 - 5, height: 300)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
if UIDevice.current.userInterfaceIdiom == .pad {
return CGSize(width: UIScreen.main.bounds.size.width / 2 - 5, height: 300)
} else {
return CGSize(width: UIScreen.mainScreen().bounds.size.width / 2 - 5, height: 200)
return CGSize(width: UIScreen.main.bounds.size.width / 2 - 5, height: 200)
}
}
}
@ -86,45 +86,45 @@ extension FromLocalViewController {
// MARK: - SKPhotoBrowserDelegate
extension FromLocalViewController {
func didShowPhotoAtIndex(index: Int) {
collectionView.visibleCells().forEach({$0.hidden = false})
collectionView.cellForItemAtIndexPath(NSIndexPath(forItem: index, inSection: 0))?.hidden = true
func didShowPhotoAtIndex(_ index: Int) {
collectionView.visibleCells.forEach({$0.isHidden = false})
collectionView.cellForItem(at: IndexPath(item: index, section: 0))?.isHidden = true
}
func willDismissAtPageIndex(index: Int) {
collectionView.visibleCells().forEach({$0.hidden = false})
collectionView.cellForItemAtIndexPath(NSIndexPath(forItem: index, inSection: 0))?.hidden = true
func willDismissAtPageIndex(_ index: Int) {
collectionView.visibleCells.forEach({$0.isHidden = false})
collectionView.cellForItem(at: IndexPath(item: index, section: 0))?.isHidden = true
}
func willShowActionSheet(photoIndex: Int) {
func willShowActionSheet(_ photoIndex: Int) {
// do some handle if you need
}
func didDismissAtPageIndex(index: Int) {
collectionView.cellForItemAtIndexPath(NSIndexPath(forItem: index, inSection: 0))?.hidden = false
func didDismissAtPageIndex(_ index: Int) {
collectionView.cellForItem(at: IndexPath(item: index, section: 0))?.isHidden = false
}
func didDismissActionSheetWithButtonIndex(buttonIndex: Int, photoIndex: Int) {
func didDismissActionSheetWithButtonIndex(_ buttonIndex: Int, photoIndex: Int) {
// handle dismissing custom actions
}
func removePhoto(browser: SKPhotoBrowser, index: Int, reload: (() -> Void)) {
func removePhoto(_ browser: SKPhotoBrowser, index: Int, reload: (() -> Void)) {
reload()
}
func viewForPhoto(browser: SKPhotoBrowser, index: Int) -> UIView? {
return collectionView.cellForItemAtIndexPath(NSIndexPath(forItem: index, inSection: 0))
func viewForPhoto(_ browser: SKPhotoBrowser, index: Int) -> UIView? {
return collectionView.cellForItem(at: IndexPath(item: index, section: 0))
}
}
// MARK: - private
private extension FromLocalViewController {
private func setupTestData() {
func setupTestData() {
images = createLocalPhotos()
}
private func setupCollectionView() {
func setupCollectionView() {
collectionView.delegate = self
collectionView.dataSource = self
}
@ -166,4 +166,4 @@ var caption = ["Lorem Ipsum is simply dummy text of the printing and typesetting
"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
"It has survived not only five centuries, but also the leap into electronic typesetting",
"remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.",
]
]

View File

@ -18,31 +18,31 @@ class FromWebViewController: UIViewController, SKPhotoBrowserDelegate {
super.viewDidLoad()
SKCache.sharedCache.imageCache = CustomImageCache()
imageView.sd_setImageWithURL(NSURL(string: "https://placehold.jp/1500x1500.png")) {
guard let url = $0.3.absoluteString else { return }
SKCache.sharedCache.setImage($0.0, forKey: url)
imageView.sd_setImage(with: URL(string: "https://placehold.jp/1500x1500.png")) {
guard let url = $0.3?.absoluteString else { return }
SKCache.sharedCache.setImage($0.0!, forKey: url)
}
}
@IBAction func pushButton(sender: AnyObject) {
@IBAction func pushButton(_ sender: AnyObject) {
let browser = SKPhotoBrowser(photos: createWebPhotos())
browser.initializePageIndex(0)
browser.delegate = self
presentViewController(browser, animated: true, completion: nil)
present(browser, animated: true, completion: nil)
}
}
// MARK: - SKPhotoBrowserDelegate
extension FromWebViewController {
func didDismissAtPageIndex(index: Int) {
func didDismissAtPageIndex(_ index: Int) {
}
func didDismissActionSheetWithButtonIndex(buttonIndex: Int, photoIndex: Int) {
func didDismissActionSheetWithButtonIndex(_ buttonIndex: Int, photoIndex: Int) {
}
func removePhoto(browser: SKPhotoBrowser, index: Int, reload: (() -> Void)) {
func removePhoto(_ browser: SKPhotoBrowser, index: Int, reload: (() -> Void)) {
SKCache.sharedCache.removeImageForKey("somekey")
reload()
}
@ -66,19 +66,19 @@ class CustomImageCache: SKImageCacheable {
init() {
let cache = SDImageCache(namespace: "com.suzuki.custom.cache")
self.cache = cache
self.cache = cache!
}
func imageForKey(key: String) -> UIImage? {
guard let image = cache.imageFromDiskCacheForKey(key) else { return nil }
func imageForKey(_ key: String) -> UIImage? {
guard let image = cache.imageFromDiskCache(forKey: key) else { return nil }
return image
}
func setImage(image: UIImage, forKey key: String) {
cache.storeImage(image, forKey: key)
func setImage(_ image: UIImage, forKey key: String) {
cache.store(image, forKey: key)
}
func removeImageForKey(key: String) {
func removeImageForKey(_ key: String) {
}
}

View File

@ -46,10 +46,14 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSPhotoLibraryUsageDescription</key>
<string>Used to get photos</string>
<key>NSCameraUsageDescription</key>
<string>Used to take photos</string>
</dict>
</plist>