Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add caption support on both normal and fullscreen controller #391

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Example/ImageSlideshow.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
D0E8A9F51D97EB94007EC517 /* UIImage+AspectFit.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */; };
D0E8A9F61D97EB94007EC517 /* UIImageView+Tools.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */; };
D0E8A9F71D97EB94007EC517 /* ZoomAnimatedTransitioning.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */; };
E6D20C7F24DD6427005CFB3C /* arrow-right-64x.png in Resources */ = {isa = PBXBuildFile; fileRef = E6D20C7D24DD6426005CFB3C /* arrow-right-64x.png */; };
E6D20C8024DD6427005CFB3C /* arrow-left-64x.png in Resources */ = {isa = PBXBuildFile; fileRef = E6D20C7E24DD6426005CFB3C /* arrow-left-64x.png */; };
F539204C210F03610057EFB3 /* SwiftSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = F539204B210F03600057EFB3 /* SwiftSupport.swift */; };
F802998F20CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; };
F802999020CE9EA7009D64DD /* PageIndicatorPosition.swift in Sources */ = {isa = PBXBuildFile; fileRef = F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */; };
Expand Down Expand Up @@ -74,6 +76,8 @@
D0E8A9EE1D97EB94007EC517 /* UIImage+AspectFit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+AspectFit.swift"; path = "../../ImageSlideshow/Classes/Core/UIImage+AspectFit.swift"; sourceTree = "<group>"; };
D0E8A9EF1D97EB94007EC517 /* UIImageView+Tools.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImageView+Tools.swift"; path = "../../ImageSlideshow/Classes/Core/UIImageView+Tools.swift"; sourceTree = "<group>"; };
D0E8A9F01D97EB94007EC517 /* ZoomAnimatedTransitioning.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ZoomAnimatedTransitioning.swift; path = ../../ImageSlideshow/Classes/Core/ZoomAnimatedTransitioning.swift; sourceTree = "<group>"; };
E6D20C7D24DD6426005CFB3C /* arrow-right-64x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "arrow-right-64x.png"; path = "../../../ImageSlideshow/Assets/arrow-right-64x.png"; sourceTree = "<group>"; };
E6D20C7E24DD6426005CFB3C /* arrow-left-64x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "arrow-left-64x.png"; path = "../../../ImageSlideshow/Assets/arrow-left-64x.png"; sourceTree = "<group>"; };
F539204B210F03600057EFB3 /* SwiftSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftSupport.swift; path = ../../ImageSlideshow/Classes/Core/SwiftSupport.swift; sourceTree = "<group>"; };
F802998E20CE9EA7009D64DD /* PageIndicatorPosition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PageIndicatorPosition.swift; path = ../../ImageSlideshow/Classes/Core/PageIndicatorPosition.swift; sourceTree = "<group>"; };
FD45C56C18E7B8EC08371B86 /* Pods-ImageSlideshow_Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ImageSlideshow_Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ImageSlideshow_Example/Pods-ImageSlideshow_Example.debug.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -198,6 +202,8 @@
D00C7A2420B4C05C00E5725B /* Resources */ = {
isa = PBXGroup;
children = (
E6D20C7E24DD6426005CFB3C /* arrow-left-64x.png */,
E6D20C7D24DD6426005CFB3C /* arrow-right-64x.png */,
D00C7A2620B4C0A100E5725B /* [email protected] */,
D00C7A2520B4C0A000E5725B /* [email protected] */,
);
Expand Down Expand Up @@ -367,8 +373,10 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E6D20C7F24DD6427005CFB3C /* arrow-right-64x.png in Resources */,
D00C7A2720B4C0A100E5725B /* [email protected] in Resources */,
D00C7A2820B4C0A100E5725B /* [email protected] in Resources */,
E6D20C8024DD6427005CFB3C /* arrow-left-64x.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
Binary file added ImageSlideshow/Assets/arrow-left-64x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ImageSlideshow/Assets/arrow-right-64x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ open class FullScreenSlideshowViewController: UIViewController {
open var slideshow: ImageSlideshow = {
let slideshow = ImageSlideshow()
slideshow.zoomEnabled = true
slideshow.isFullScreenSlideShow = true
slideshow.contentScaleMode = UIViewContentMode.scaleAspectFit
slideshow.pageIndicatorPosition = PageIndicatorPosition(horizontal: .center, vertical: .bottom)
// turns off the timer
Expand All @@ -21,6 +22,12 @@ open class FullScreenSlideshowViewController: UIViewController {

return slideshow
}()

/// Left Arrow button
open var leftArrowButton = UIButton()

/// Right Arrow button
open var rightArrowButton = UIButton()

/// Close button
open var closeButton = UIButton()
Expand All @@ -47,6 +54,8 @@ open class FullScreenSlideshowViewController: UIViewController {
}
}

fileprivate var hideInfo = true

fileprivate var isInit = true

convenience init() {
Expand All @@ -70,11 +79,44 @@ open class FullScreenSlideshowViewController: UIViewController {
}

view.addSubview(slideshow)

let singleTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(singleTapAction))
singleTapGestureRecognizer.numberOfTapsRequired = 1
slideshow.addGestureRecognizer(singleTapGestureRecognizer)

updateUI()

// close button configuration
closeButton.setImage(UIImage(named: "ic_cross_white", in: Bundle(for: type(of: self)), compatibleWith: nil), for: UIControlState())
closeButton.addTarget(self, action: #selector(FullScreenSlideshowViewController.close), for: UIControlEvents.touchUpInside)
view.addSubview(closeButton)

// left arrow button configuration
leftArrowButton.setImage(UIImage(named: "arrow-left-64x", in: Bundle(for: type(of: self)), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate), for: UIControlState())
leftArrowButton.addTarget(self, action: #selector(FullScreenSlideshowViewController.leftArrowTap(_:)), for: UIControlEvents.touchUpInside)
view.addSubview(leftArrowButton)

// Right arrow button configuration
rightArrowButton.setImage(UIImage(named: "arrow-right-64x", in: Bundle(for: type(of: self)), compatibleWith: nil)?.withRenderingMode(.alwaysTemplate), for: UIControlState())
rightArrowButton.addTarget(self, action: #selector(FullScreenSlideshowViewController.rightArrowTap(_:)), for: UIControlEvents.touchUpInside)
view.addSubview(rightArrowButton)
leftArrowButton.translatesAutoresizingMaskIntoConstraints = false
rightArrowButton.translatesAutoresizingMaskIntoConstraints = false
leftArrowButton.backgroundColor = UIColor.black.withAlphaComponent(0.5)
rightArrowButton.backgroundColor = UIColor.black.withAlphaComponent(0.5)
leftArrowButton.tintColor = .white
rightArrowButton.tintColor = .white

closeButton.backgroundColor = UIColor.black.withAlphaComponent(0.5)

let leadingConstraint = NSLayoutConstraint(item: leftArrowButton, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1, constant: 0)
let centerLeftConstraint = NSLayoutConstraint(item: leftArrowButton, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)

let trailingConstraint = NSLayoutConstraint(item: rightArrowButton, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: 0)
let centerRightConstraint = NSLayoutConstraint(item: rightArrowButton, attribute: NSLayoutConstraint.Attribute.centerY, relatedBy: NSLayoutConstraint.Relation.equal, toItem: view, attribute: NSLayoutConstraint.Attribute.centerY, multiplier: 1, constant: 0)


NSLayoutConstraint.activate([leadingConstraint, centerLeftConstraint, trailingConstraint, centerRightConstraint])
}

override open var prefersStatusBarHidden: Bool {
Expand Down Expand Up @@ -109,6 +151,7 @@ open class FullScreenSlideshowViewController: UIViewController {
}

closeButton.frame = closeButtonFrame ?? CGRect(x: max(10, safeAreaInsets.left), y: max(10, safeAreaInsets.top), width: 40, height: 40)
closeButton.layer.cornerRadius = 20
}

slideshow.frame = view.frame
Expand All @@ -122,4 +165,26 @@ open class FullScreenSlideshowViewController: UIViewController {

dismiss(animated: true, completion: nil)
}

fileprivate func updateUI() {
closeButton.isHidden = hideInfo
rightArrowButton.isHidden = hideInfo || slideshow.slideshowItems.count < 2
leftArrowButton.isHidden = hideInfo || slideshow.slideshowItems.count < 2
slideshow.hideCaption = hideInfo
}

@objc private func rightArrowTap(_ sender: UIButton) {
let nextIndex = slideshow.currentPage + 1
slideshow.setCurrentPage(nextIndex, animated: true)
}

@objc private func leftArrowTap(_ sender: UIButton) {
let nextIndex = slideshow.currentPage - 1
slideshow.setCurrentPage(nextIndex, animated: true)
}

@objc func singleTapAction() {
hideInfo = !hideInfo
updateUI()
}
}
34 changes: 30 additions & 4 deletions ImageSlideshow/Classes/Core/ImageSlideshow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,20 @@ open class ImageSlideshow: UIView {
}
}
}

/// isFullScreenSlideShow handle fullscreen
open var isFullScreenSlideShow = false {
didSet {
reloadScrollView()
}
}

/// hide Caption handle for full screen
var hideCaption = true {
didSet {
updateCaption()
}
}

/// Enables/disables user interactions
open var draggingEnabled = true {
Expand Down Expand Up @@ -320,8 +334,9 @@ open class ImageSlideshow: UIView {

var i = 0
for image in scrollViewImages {
let item = ImageSlideshowItem(image: image, zoomEnabled: zoomEnabled, activityIndicator: activityIndicator?.create(), maximumScale: maximumScale)
let item = ImageSlideshowItem(image: image, zoomEnabled: zoomEnabled, activityIndicator: activityIndicator?.create(), maximumScale: maximumScale, isFullScreenSlideShow: isFullScreenSlideShow)
item.imageView.contentMode = contentScaleMode
item.hideCaption = hideCaption
slideshowItems.append(item)
scrollView.addSubview(item)
i += 1
Expand Down Expand Up @@ -355,6 +370,12 @@ open class ImageSlideshow: UIView {
}
}
}

private func updateCaption() {
for view in slideshowItems {
view.hideCaption = hideCaption
}
}

// MARK: - Image setting

Expand Down Expand Up @@ -537,18 +558,23 @@ open class ImageSlideshow: UIView {
- returns: FullScreenSlideshowViewController instance
*/
@discardableResult
open func presentFullScreenController(from controller: UIViewController, completion: (() -> Void)? = nil) -> FullScreenSlideshowViewController {
open func presentFullScreenController(from controller: UIViewController, contentScaleMode: UIViewContentMode = UIViewContentMode.scaleAspectFill, completion: (() -> Void)? = nil) -> FullScreenSlideshowViewController {
let fullscreen = FullScreenSlideshowViewController()
fullscreen.pageSelected = {[weak self] (page: Int) in
self?.setCurrentPage(page, animated: false)
}

let currentScaleMode = self.contentScaleMode
self.contentScaleMode = contentScaleMode
fullscreen.slideshow.contentScaleMode = contentScaleMode
fullscreen.initialPage = currentPage
fullscreen.inputs = images
slideshowTransitioningDelegate = ZoomAnimatedTransitioningDelegate(slideshowView: self, slideshowController: fullscreen)
fullscreen.transitioningDelegate = slideshowTransitioningDelegate
fullscreen.modalPresentationStyle = .custom
controller.present(fullscreen, animated: true, completion: completion)
controller.present(fullscreen, animated: true) {
self.contentScaleMode = currentScaleMode
completion?()
}

return fullscreen
}
Expand Down
79 changes: 69 additions & 10 deletions ImageSlideshow/Classes/Core/ImageSlideshowItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
/// Image view to hold the image
public let imageView = UIImageView()

/// Caption Label to show image caption
public let captionLabel = UILabel()

/// Caption Container that add caption and background color
fileprivate var captionContainerView: UIView

/// isFullScreenSlideShow ture if slider full screen controller shown
public let isFullScreenSlideShow: Bool

/// Activity indicator shown during image loading, when nil there won't be shown any
public let activityIndicator: ActivityIndicatorView?

Expand All @@ -31,6 +40,12 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {

/// Maximum zoom scale
open var maximumScale: CGFloat = 2.0

var hideCaption = false {
didSet {
updateCaption()
}
}

fileprivate var lastFrame = CGRect.zero
fileprivate var imageReleased = false
Expand All @@ -53,12 +68,25 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
- parameter image: Input Source to load the image
- parameter zoomEnabled: holds if it should be possible to zoom-in the image
*/
init(image: InputSource, zoomEnabled: Bool, activityIndicator: ActivityIndicatorView? = nil, maximumScale: CGFloat = 2.0) {
init(image: InputSource, zoomEnabled: Bool, activityIndicator: ActivityIndicatorView? = nil, maximumScale: CGFloat = 2.0, isFullScreenSlideShow: Bool) {
self.zoomEnabled = zoomEnabled
self.image = image
self.activityIndicator = activityIndicator
self.maximumScale = maximumScale

self.isFullScreenSlideShow = isFullScreenSlideShow

let captionConstraintView = UIView()
captionConstraintView.addSubview(captionLabel)
if #available(iOS 9.0, *) {
let captionStackView = UIStackView()
captionStackView.axis = .vertical
captionStackView.alignment = .leading
captionStackView.addArrangedSubview(captionConstraintView)
captionContainerView = captionStackView
} else {
captionContainerView = captionConstraintView
}

super.init(frame: CGRect.null)

imageViewWrapper.addSubview(imageView)
Expand Down Expand Up @@ -99,6 +127,22 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
singleTapGestureRecognizer!.numberOfTapsRequired = 1
singleTapGestureRecognizer!.isEnabled = false
imageViewWrapper.addGestureRecognizer(singleTapGestureRecognizer!)

captionContainerView.addSubview(captionConstraintView)
imageViewWrapper.addSubview(captionContainerView)
captionLabel.textColor = .white
captionLabel.numberOfLines = 0
captionConstraintView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
captionLabel.translatesAutoresizingMaskIntoConstraints = false
captionContainerView.translatesAutoresizingMaskIntoConstraints = false

let leadingConstraint = NSLayoutConstraint(item: captionLabel, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: captionConstraintView, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1, constant: 5)
let trailingConstraint = NSLayoutConstraint(item: captionLabel, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: captionConstraintView, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: -5)
let topConstraint = NSLayoutConstraint(item: captionLabel, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: captionConstraintView, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 5)
let bottomConstraint = NSLayoutConstraint(item: captionLabel, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: captionConstraintView, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: -5)

NSLayoutConstraint.activate([topConstraint, leadingConstraint, bottomConstraint, trailingConstraint,])

}

required public init?(coder aDecoder: NSCoder) {
Expand Down Expand Up @@ -131,6 +175,10 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {

contentSize = imageViewWrapper.frame.size
maximumZoomScale = calculateMaximumScale()

let leadingConstraint = NSLayoutConstraint(item: captionContainerView, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: imageViewWrapper, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1, constant: 20)
let trailingConstraint = NSLayoutConstraint(item: captionContainerView, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: imageViewWrapper, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: -20)
NSLayoutConstraint.activate([leadingConstraint, trailingConstraint,])
}

/// Request to load Image Source to Image View
Expand All @@ -139,18 +187,24 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
isLoading = true
imageReleased = false
activityIndicator?.show()
image.load(to: self.imageView) {[weak self] image in
image.load(to: self.imageView) {[weak self] (image, caption, captionBottomConstraint, showCaptionOnlyInFullScreen) in
guard let self = self else { return }
// set image to nil if there was a release request during the image load
if let imageRelease = self?.imageReleased, imageRelease {
self?.imageView.image = nil
if self.imageReleased {
self.imageView.image = nil
} else {
self?.imageView.image = image
self.imageView.image = image
}
self?.activityIndicator?.hide()
self?.loadFailed = image == nil
self?.isLoading = false
self.captionLabel.text = caption
self.captionContainerView.isHidden = self.hideCaption || (!self.isFullScreenSlideShow && showCaptionOnlyInFullScreen) || (caption ?? "").isEmpty

self?.setNeedsLayout()
NSLayoutConstraint(item: self.captionContainerView, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.imageViewWrapper, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: captionBottomConstraint).isActive = true

self.activityIndicator?.hide()
self.loadFailed = image == nil
self.isLoading = false

self.setNeedsLayout()
}
}
}
Expand All @@ -169,6 +223,11 @@ open class ImageSlideshowItem: UIScrollView, UIScrollViewDelegate {
self.loadImage()
}


private func updateCaption() {
self.captionContainerView.isHidden = self.hideCaption || (captionLabel.text ?? "").isEmpty
}

// MARK: - Image zoom & size

func isZoomed() -> Bool {
Expand Down
Loading