diff --git a/README.md b/README.md index daee36d3..a99188ef 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,18 @@ var images = [SKPhoto]() let photo = SKPhoto.photoWithImage(UIImage())// add some UIImage images.append(photo) -// 2. create PhotoBrowser Instance, and present from your viewController. +// 2. for adding video +// Local file +if let url1 = Bundle.main.url(forResource: "bunny", withExtension: "mp4") { + images.append(SKPhoto.videoWithURL(url1)) +} + +// From internet +if let url2 = URL(string: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4") { + images.append(SKPhoto.videoWithURL(url2)) +} + +// 3. create PhotoBrowser Instance, and present from your viewController. let browser = SKPhotoBrowser(photos: images) browser.initializePageIndex(0) present(browser, animated: true, completion: {}) diff --git a/SKPhotoBrowser/SKLocalPhoto.swift b/SKPhotoBrowser/SKLocalPhoto.swift index 87a73f1e..92968fb6 100644 --- a/SKPhotoBrowser/SKLocalPhoto.swift +++ b/SKPhotoBrowser/SKLocalPhoto.swift @@ -17,6 +17,7 @@ open class SKLocalPhoto: NSObject, SKPhotoProtocol { open var shouldCachePhotoURLImage: Bool = false open var caption: String? open var index: Int = 0 + public var videoURL: URL? override init() { super.init() @@ -59,6 +60,13 @@ open class SKLocalPhoto: NSObject, SKPhotoProtocol { NotificationCenter.default.post(name: Notification.Name(rawValue: SKPHOTO_LOADING_DID_END_NOTIFICATION), object: self) } + // Check if we have a video URL + // https://github.com/engasix/ + + open func isVideo() -> Bool { + return self.videoURL != nil + } + // MARK: - class func open class func photoWithImageURL(_ url: String) -> SKLocalPhoto { return SKLocalPhoto(url: url) diff --git a/SKPhotoBrowser/SKPagingScrollView.swift b/SKPhotoBrowser/SKPagingScrollView.swift index 3332f4d9..d7fecca5 100644 --- a/SKPhotoBrowser/SKPagingScrollView.swift +++ b/SKPhotoBrowser/SKPagingScrollView.swift @@ -138,13 +138,21 @@ class SKPagingScrollView: UIScrollView { continue } - let page: SKZoomingScrollView = SKZoomingScrollView(frame: frame, browser: browser) - page.frame = frameForPageAtIndex(index) - page.tag = index + pageIndexTagOffset let photo = browser.photos[index] + + let page = SKZoomingScrollView(frame: frame, browser: browser) page.photo = photo + + if photo.isVideo() { + page.setupVideo() + } else { + page.setupImage() + } + + page.frame = frameForPageAtIndex(photo.index) + page.tag = photo.index + pageIndexTagOffset if let thumbnail = browser.animator.senderOriginImage, - index == browser.initPageIndex, + photo.index == browser.initPageIndex, photo.underlyingImage == nil { page.displayImage(thumbnail) } @@ -153,8 +161,8 @@ class SKPagingScrollView: UIScrollView { addSubview(page) // if exists caption, insert - if let captionView: SKCaptionView = createCaptionView(index) { - captionView.frame = frameForCaptionView(captionView, index: index) + if let captionView: SKCaptionView = createCaptionView(photo.index) { + captionView.frame = frameForCaptionView(captionView, index: photo.index) captionView.alpha = browser.areControlsHidden() ? 0 : 1 addSubview(captionView) // ref val for control diff --git a/SKPhotoBrowser/SKPhoto.swift b/SKPhotoBrowser/SKPhoto.swift index 874ef9e8..f8dda181 100644 --- a/SKPhotoBrowser/SKPhoto.swift +++ b/SKPhotoBrowser/SKPhoto.swift @@ -15,19 +15,23 @@ import SKPhotoBrowserObjC var index: Int { get set } var underlyingImage: UIImage! { get } var caption: String? { get } + var videoURL: URL? { get } var contentMode: UIView.ContentMode { get set } func loadUnderlyingImageAndNotify() func checkCache() + func isVideo () -> Bool } // MARK: - SKPhoto open class SKPhoto: NSObject, SKPhotoProtocol { + open var index: Int = 0 open var underlyingImage: UIImage! open var caption: String? open var contentMode: UIView.ContentMode = .scaleAspectFill open var shouldCachePhotoURLImage: Bool = false open var photoURL: String! + open var videoURL: URL? override init() { super.init() @@ -49,6 +53,11 @@ open class SKPhoto: NSObject, SKPhotoProtocol { underlyingImage = holder } + convenience init(videoURL: URL?) { + self.init() + self.videoURL = videoURL + } + open func checkCache() { guard let photoURL = photoURL else { return @@ -129,6 +138,12 @@ open class SKPhoto: NSObject, SKPhotoProtocol { NotificationCenter.default.post(name: Notification.Name(rawValue: SKPHOTO_LOADING_DID_END_NOTIFICATION), object: self) } + // Check if we have a video URL + // https://github.com/engasix/ + + open func isVideo() -> Bool { + return self.videoURL != nil + } } // MARK: - Static Function @@ -145,4 +160,8 @@ extension SKPhoto { public static func photoWithImageURL(_ url: String, holder: UIImage?) -> SKPhoto { return SKPhoto(url: url, holder: holder) } + + public static func videoWithURL(_ url: URL) -> SKPhoto { + return SKPhoto(videoURL: url) + } } diff --git a/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton.png b/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton.png new file mode 100644 index 00000000..fdabf159 Binary files /dev/null and b/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton.png differ diff --git a/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton@2x.png b/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton@2x.png new file mode 100644 index 00000000..3e5d54ae Binary files /dev/null and b/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton@2x.png differ diff --git a/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton@3x.png b/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton@3x.png new file mode 100644 index 00000000..3fc49be6 Binary files /dev/null and b/SKPhotoBrowser/SKPhotoBrowser.bundle/images/PlayButton@3x.png differ diff --git a/SKPhotoBrowser/SKPhotoBrowser.swift b/SKPhotoBrowser/SKPhotoBrowser.swift index e8d8cb3d..f0117f9e 100644 --- a/SKPhotoBrowser/SKPhotoBrowser.swift +++ b/SKPhotoBrowser/SKPhotoBrowser.swift @@ -108,12 +108,12 @@ open class SKPhotoBrowser: UIViewController { // MARK: - override override open func viewDidLoad() { super.viewDidLoad() - configureAppearance() - configurePagingScrollView() - configureGestureControl() - configureActionView() - configurePaginationView() - configureToolbar() + configureAppearance() + configurePagingScrollView() + configureGestureControl() + configureActionView() + configurePaginationView() + configureToolbar() animator.willPresent(self) } diff --git a/SKPhotoBrowser/SKZoomingScrollView.swift b/SKPhotoBrowser/SKZoomingScrollView.swift index 8d135127..a4979e7f 100644 --- a/SKPhotoBrowser/SKZoomingScrollView.swift +++ b/SKPhotoBrowser/SKZoomingScrollView.swift @@ -7,21 +7,19 @@ // import UIKit +import AVFoundation open class SKZoomingScrollView: UIScrollView { + var captionView: SKCaptionView! - var photo: SKPhotoProtocol! { - didSet { - imageView.image = nil - if photo != nil && photo.underlyingImage != nil { - displayImage(complete: true) - return - } - if photo != nil { - displayImage(complete: false) - } - } - } + var photo: SKPhotoProtocol! + + var videoPlayer: AVPlayer? + var videoPlayerLayer: AVPlayerLayer? + var imageViewVideoButton: UIImageView? + + private var isSetup = false + private var isVideoSetup = false fileprivate weak var browser: SKPhotoBrowser? @@ -31,78 +29,130 @@ open class SKZoomingScrollView: UIScrollView { required public init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) - setup() + // setup() } override init(frame: CGRect) { super.init(frame: frame) - setup() + // setup() } convenience init(frame: CGRect, browser: SKPhotoBrowser) { self.init(frame: frame) self.browser = browser - setup() + // setup() } deinit { browser = nil } - func setup() { - // tap - tapView = SKDetectingView(frame: bounds) - tapView.delegate = self - tapView.backgroundColor = .clear - tapView.autoresizingMask = [.flexibleHeight, .flexibleWidth] - addSubview(tapView) - - // image - imageView = SKDetectingImageView(frame: frame) - imageView.delegate = self - imageView.contentMode = .bottom - imageView.backgroundColor = .clear - addSubview(imageView) + func setupImage () { - // indicator - indicatorView = SKIndicatorView(frame: frame) - addSubview(indicatorView) + if !isSetup { + // tap + tapView = SKDetectingView(frame: bounds) + tapView.delegate = self + tapView.backgroundColor = .clear + tapView.autoresizingMask = [.flexibleHeight, .flexibleWidth] + addSubview(tapView) + + // image + imageView = SKDetectingImageView(frame: frame) + imageView.delegate = self + imageView.contentMode = .bottom + imageView.backgroundColor = .clear + addSubview(imageView) + + // indicator + indicatorView = SKIndicatorView(frame: frame) + addSubview(indicatorView) + + // self + // backgroundColor = .clear + delegate = self + showsHorizontalScrollIndicator = SKPhotoBrowserOptions.displayHorizontalScrollIndicator + showsVerticalScrollIndicator = SKPhotoBrowserOptions.displayVerticalScrollIndicator + autoresizingMask = [.flexibleWidth, .flexibleTopMargin, .flexibleBottomMargin, .flexibleRightMargin, .flexibleLeftMargin] + + isSetup = true + layoutSubviews() + } - // self - backgroundColor = .clear - delegate = self - showsHorizontalScrollIndicator = SKPhotoBrowserOptions.displayHorizontalScrollIndicator - showsVerticalScrollIndicator = SKPhotoBrowserOptions.displayVerticalScrollIndicator - autoresizingMask = [.flexibleWidth, .flexibleTopMargin, .flexibleBottomMargin, .flexibleRightMargin, .flexibleLeftMargin] + imageView.image = nil + if photo.isVideo() { + backgroundColor = .systemPink + } + if photo != nil && photo.underlyingImage != nil { + displayImage(complete: true) + return + } + if photo != nil { + displayImage(complete: false) + } } - // MARK: - override - - open override func layoutSubviews() { - tapView.frame = bounds - indicatorView.frame = bounds - - super.layoutSubviews() - - let boundsSize = bounds.size - var frameToCenter = imageView.frame + func setupVideo () { - // horizon - if frameToCenter.size.width < boundsSize.width { - frameToCenter.origin.x = floor((boundsSize.width - frameToCenter.size.width) / 2) - } else { - frameToCenter.origin.x = 0 + // tap + if !isVideoSetup { + isVideoSetup = true + tapView = SKDetectingView(frame: bounds) + tapView.delegate = self + tapView.backgroundColor = .clear + tapView.autoresizingMask = [.flexibleHeight, .flexibleWidth] + addSubview(tapView) } - // vertical - if frameToCenter.size.height < boundsSize.height { - frameToCenter.origin.y = floor((boundsSize.height - frameToCenter.size.height) / 2) - } else { - frameToCenter.origin.y = 0 + + if let url = photo.videoURL { + + imageViewVideoButton = UIImageView(frame: CGRect(x: 0, y: 0, + width: 50, height: 50)) + + imageViewVideoButton?.image = UIImage(named: "PlayButton.png") + + addSubview(imageViewVideoButton!) + imageViewVideoButton?.center = center + + videoPlayer = AVPlayer(url: url) + videoPlayerLayer = AVPlayerLayer(player: videoPlayer) + videoPlayerLayer?.frame = self.bounds + layer.addSublayer(videoPlayerLayer!) + + bringSubviewToFront(imageViewVideoButton!) } - // Center - if !imageView.frame.equalTo(frameToCenter) { - imageView.frame = frameToCenter + } + + // MARK: - override + + open override func layoutSubviews() { + if isSetup { + tapView.frame = bounds + indicatorView.frame = bounds + + super.layoutSubviews() + + let boundsSize = bounds.size + var frameToCenter = imageView.frame + + // horizon + if frameToCenter.size.width < boundsSize.width { + frameToCenter.origin.x = floor((boundsSize.width - frameToCenter.size.width) / 2) + } else { + frameToCenter.origin.x = 0 + } + // vertical + if frameToCenter.size.height < boundsSize.height { + frameToCenter.origin.y = floor((boundsSize.height - frameToCenter.size.height) / 2) + } else { + frameToCenter.origin.y = 0 + } + + // Center + if !imageView.frame.equalTo(frameToCenter) { + imageView.frame = frameToCenter + } } } @@ -162,6 +212,15 @@ open class SKZoomingScrollView: UIScrollView { } open func prepareForReuse() { + + if let layer = videoPlayerLayer { + layer.removeFromSuperlayer() + } + + imageViewVideoButton = nil + videoPlayerLayer = nil + videoPlayer = nil + photo = nil if captionView != nil { captionView.removeFromSuperview() @@ -265,6 +324,20 @@ extension SKZoomingScrollView: UIScrollViewDelegate { extension SKZoomingScrollView: SKDetectingViewDelegate { func handleSingleTap(_ view: UIView, touch: UITouch) { + + if photo.isVideo() { + + if videoPlayer?.rate != 1.0 { + videoPlayer?.play() + imageViewVideoButton?.isHidden = true + } else { + videoPlayer?.pause() + imageViewVideoButton?.isHidden = false + } + + return + } + guard let browser = browser else { return } @@ -280,6 +353,11 @@ extension SKZoomingScrollView: SKDetectingViewDelegate { } func handleDoubleTap(_ view: UIView, touch: UITouch) { + + if photo.isVideo() { + return + } + if SKPhotoBrowserOptions.enableZoomBlackArea == true { let needPoint = getViewFramePercent(view, touch: touch) handleDoubleTap(needPoint)