Skip to content
Open
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
154 changes: 148 additions & 6 deletions MediaSlideshow/Source/MediaSlideshow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public protocol MediaSlideshowDelegate: class {
@objc optional func mediaSlideshowDidEndDecelerating(_ mediaSlideshow: MediaSlideshow)
}

/**
/**
Used to represent position of the Page Control
- hidden: Page Control is hidden
- insideScrollView: Page Control is inside image slideshow
Expand Down Expand Up @@ -73,6 +73,14 @@ open class MediaSlideshow: UIView {
reloadScrollView()
}
}

open var circular = true {
didSet {
if sources.count > 0 {
setMediaSources(sources)
}
}
}

open var pageIndicator: PageIndicatorView? {
didSet {
Expand Down Expand Up @@ -177,6 +185,14 @@ open class MediaSlideshow: UIView {
}
}

/// Image change interval, zero stops the auto-scrolling
open var slideshowInterval = 0.0 {
didSet {
slideshowTimer?.invalidate()
slideshowTimer = nil
setTimerIfNeeded()
}
}
/// Image preload configuration, can be sed to .fixed to enable lazy load or .all
open var preload = ImagePreload.all

Expand All @@ -189,6 +205,8 @@ open class MediaSlideshow: UIView {
}
}

fileprivate var slideshowTimer: Timer?
fileprivate var scrollViewImages = [MediaSource]()
fileprivate var isAnimating: Bool = false

/// Transitioning delegate to manage the transition to full screen controller
Expand Down Expand Up @@ -242,9 +260,15 @@ open class MediaSlideshow: UIView {
pageIndicator = UIPageControl()
}

setTimerIfNeeded()
layoutScrollView()
}

open override func removeFromSuperview() {
super.removeFromSuperview()
pauseTimer()
}

open override func layoutSubviews() {
super.layoutSubviews()

Expand Down Expand Up @@ -331,10 +355,32 @@ open class MediaSlideshow: UIView {
*/
public func setMediaSources(_ sources: [MediaSource]) {
self.sources = sources

pageIndicator?.numberOfPages = sources.count

// in circular mode we add dummy first and last image to enable smooth scrolling
if circular && sources.count > 1 {
var scImages = [MediaSource]()

if let last = sources.last {
scImages.append(last)
}
scImages += sources
if let first = sources.first {
scImages.append(first)
}

scrollViewImages = scImages
} else {
scrollViewImages = sources
}


reloadScrollView()
layoutScrollView()
layoutPageControl()
setTimerIfNeeded()

}

// MARK: paging methods
Expand All @@ -345,7 +391,13 @@ open class MediaSlideshow: UIView {
- parameter animated: true if animate the change
*/
open func setCurrentPage(_ newPage: Int, animated: Bool) {
setScrollViewPage(newPage, animated: animated)
var pageOffset = newPage
if circular && (scrollViewImages.count > 1) {
pageOffset += 1
}

setScrollViewPage(pageOffset, animated: animated)

}

/**
Expand All @@ -362,6 +414,24 @@ open class MediaSlideshow: UIView {
}
}
}

fileprivate func setTimerIfNeeded() {
if slideshowInterval > 0 && scrollViewImages.count > 1 && slideshowTimer == nil {
slideshowTimer = Timer.scheduledTimer(timeInterval: slideshowInterval, target: self, selector: #selector(MediaSlideshow.slideshowTick(_:)), userInfo: nil, repeats: true)
}
}

func slideshowTick(_ timer: Timer) {
let page = scrollView.frame.size.width > 0 ? Int(scrollView.contentOffset.x / scrollView.frame.size.width) : 0
var nextPage = page + 1

if !circular && page == scrollViewImages.count - 1 {
nextPage = 0
}

setScrollViewPage(nextPage, animated: true)
}


fileprivate func setCurrentPageForScrollViewPage(_ page: Int) {
if scrollViewPage != page {
Expand All @@ -381,32 +451,86 @@ open class MediaSlideshow: UIView {
}

fileprivate func currentPageForScrollViewPage(_ page: Int) -> Int {
page
if circular {
if page == 0 {
// first page contains the last image
return Int(sources.count) - 1
} else if page == scrollViewImages.count - 1 {
// last page contains the first image
return 0
} else {
return page - 1
}
} else {
return page
}
}

fileprivate func restartTimer() {
if slideshowTimer?.isValid != nil {
slideshowTimer?.invalidate()
slideshowTimer = nil
}

setTimerIfNeeded()
}


/// Stops slideshow timer
open func pauseTimer() {
slideshowTimer?.invalidate()
slideshowTimer = nil
}

/// Restarts slideshow timer
open func unpauseTimer() {
setTimerIfNeeded()
}

@available(*, deprecated, message: "use pauseTimer instead")
open func pauseTimerIfNeeded() {
pauseTimer()
}

@available(*, deprecated, message: "use unpauseTimer instead")
open func unpauseTimerIfNeeded() {
unpauseTimer()
}

/**
Change the page to the next one
- Parameter animated: true if animate the change
*/
open func nextPage(animated: Bool) {
if !circular && currentPage == sources.count - 1 {
return
}
if isAnimating {
return
}

setCurrentPage(currentPage + 1, animated: animated)
restartTimer()
}

/**
Change the page to the previous one
- Parameter animated: true if animate the change
*/
open func previousPage(animated: Bool) {
if !circular && currentPage == 0 {
return
}
if isAnimating {
return
}
let newPage = scrollViewPage > 0 ? scrollViewPage - 1 : sources.count - 3

let newPage = scrollViewPage > 0 ? scrollViewPage - 1 : scrollViewImages.count - 3
setScrollViewPage(newPage, animated: animated)
restartTimer()
}


@objc private func pageControlValueChanged() {
if let currentPage = pageIndicator?.page {
setCurrentPage(currentPage, animated: true)
Expand All @@ -417,6 +541,7 @@ open class MediaSlideshow: UIView {
extension MediaSlideshow: UIScrollViewDelegate {

open func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
restartTimer()
willBeginDragging?()
delegate?.mediaSlideshowWillBeginDragging?(self)
}
Expand All @@ -426,15 +551,32 @@ extension MediaSlideshow: UIScrollViewDelegate {
didEndDecelerating?()
delegate?.mediaSlideshowDidEndDecelerating?(self)
}

//
// open func scrollViewDidScroll(_ scrollView: UIScrollView) {
// // Updates the page indicator as the user scrolls (#204). Not called when not dragging to prevent flickers
// // when interacting with PageControl directly (#376).
// if scrollView.isDragging {
// pageIndicator?.page = currentPageForScrollViewPage(primaryVisiblePage)
// }
// }
open func scrollViewDidScroll(_ scrollView: UIScrollView) {
if circular && (scrollViewImages.count > 1) {
let regularContentOffset = scrollView.frame.size.width * CGFloat(sources.count)

if scrollView.contentOffset.x >= scrollView.frame.size.width * CGFloat(sources.count + 1) {
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x - regularContentOffset, y: 0)
} else if scrollView.contentOffset.x <= 0 {
scrollView.contentOffset = CGPoint(x: scrollView.contentOffset.x + regularContentOffset, y: 0)
}
}

// Updates the page indicator as the user scrolls (#204). Not called when not dragging to prevent flickers
// when interacting with PageControl directly (#376).
if scrollView.isDragging {
pageIndicator?.page = currentPageForScrollViewPage(primaryVisiblePage)
}
}

public func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
isAnimating = false
}
Expand Down