Compare commits
44 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
671e157f06 | |
|
|
5d342d7a3b | |
|
|
8366afeb44 | |
|
|
b8156c7d6b | |
|
|
f67abbc97a | |
|
|
8be7dfa8c3 | |
|
|
08b857a00b | |
|
|
378973db1d | |
|
|
b49fa26960 | |
|
|
660ebf5a31 | |
|
|
36e86dad64 | |
|
|
29f3643a7a | |
|
|
828fe43d5a | |
|
|
5f7f93cb6c | |
|
|
5c473baa98 | |
|
|
cebe57d401 | |
|
|
700264f1b9 | |
|
|
ef66295f32 | |
|
|
78da87c180 | |
|
|
92734dd5d3 | |
|
|
21721e4445 | |
|
|
5062b3821a | |
|
|
dee700fbea | |
|
|
53436a2288 | |
|
|
ae76f6487a | |
|
|
af3d342eb1 | |
|
|
b346984634 | |
|
|
dcd663a841 | |
|
|
2ba8a3c60d | |
|
|
7db1d4d277 | |
|
|
1ce00437d4 | |
|
|
3dc46dd011 | |
|
|
17f8af1f62 | |
|
|
c665147348 | |
|
|
b7a030506b | |
|
|
4dc2f9717f | |
|
|
7a4a26e42f | |
|
|
b022bd0c44 | |
|
|
985e9d31fe | |
|
|
107ad78354 | |
|
|
d42a43a7ea | |
|
|
85d58f5888 | |
|
|
b595a5beb7 | |
|
|
c719c4363f |
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0700"
|
||||
LastUpgradeVersion = "0800"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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]?
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ DEPENDENCIES:
|
|||
SPEC CHECKSUMS:
|
||||
SDWebImage: 35f9627a3e44b4f292a8a8ce6a531fa488239b91
|
||||
|
||||
COCOAPODS: 0.39.0
|
||||
PODFILE CHECKSUM: a32274f1ce260fbc242dfd48f2b1af8a84a5bc0e
|
||||
|
||||
COCOAPODS: 1.1.0.beta.2
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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:.
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.",
|
||||
]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue