123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460 |
- import UIKit
- public enum PageControlStyle {
- case none
- case system
- case fill
- case pill
- case snake
- }
- public typealias LLdidSelectItemAtIndexClosure = (NSInteger) -> Void
- @IBDesignable open class LLCycleScrollView: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate {
-
-
- open var autoScroll: Bool? = true {
- didSet {
- invalidateTimer()
- if autoScroll! {
- setupTimer()
- }
- }
- }
-
- open var infiniteLoop: Bool? = true {
- didSet {
- if imagePaths.count > 0 {
- let temp = imagePaths
- imagePaths = temp
- }
- }
- }
-
- open var scrollDirection: UICollectionViewScrollDirection? = .horizontal {
- didSet {
- flowLayout?.scrollDirection = scrollDirection!
- if scrollDirection == .horizontal {
- position = .centeredHorizontally
- } else {
- position = .centeredVertically
- }
- }
- }
-
- @IBInspectable open var autoScrollTimeInterval: Double = 2.0 {
- didSet {
- autoScroll = true
- }
- }
-
- @IBInspectable open var placeHolderImage: UIImage? = nil {
- didSet {
- if placeHolderImage != nil {
- placeHolderViewImage = placeHolderImage
- }
- }
- }
-
- @IBInspectable open var coverImage: UIImage? = nil {
- didSet {
- if coverImage != nil {
- coverViewImage = coverImage
- }
- }
- }
-
- open var imageViewContentMode: UIViewContentMode? {
- didSet {
- collectionView.reloadData()
- }
- }
-
-
- open var pageControlTintColor: UIColor = UIColor.lightGray {
- didSet {
- setupPageControl()
- }
- }
-
- open var pageControlCurrentPageColor: UIColor = UIColor.white {
- didSet {
- setupPageControl()
- }
- }
-
-
- open var customPageControlStyle: PageControlStyle = .system {
- didSet {
- setupPageControl()
- }
- }
-
- open var customPageControlTintColor: UIColor = UIColor.white {
- didSet {
- setupPageControl()
- }
- }
-
- open var customPageControlIndicatorPadding: CGFloat = 8 {
- didSet {
- setupPageControl()
- }
- }
-
-
- open var FillPageControlIndicatorRadius: CGFloat = 4 {
- didSet {
- setupPageControl()
- }
- }
-
-
- open var customPageControlInActiveTintColor: UIColor = UIColor(white: 1, alpha: 0.3) {
- didSet {
- setupPageControl()
- }
- }
-
- @IBInspectable open var collectionViewBackgroundColor: UIColor! = UIColor.clear
-
- open var imagePaths: Array<String> = [] {
- didSet {
- totalItemsCount = infiniteLoop! ? imagePaths.count * 100 : imagePaths.count
- if imagePaths.count != 1 {
- collectionView.isScrollEnabled = true
- autoScroll = true
- } else {
- collectionView.isScrollEnabled = false
- }
- setupPageControl()
- collectionView.reloadData()
- }
- }
-
- open var titles: Array<String> = []
-
-
- fileprivate let identifier = "LLCycleScrollViewCell"
-
- fileprivate var totalItemsCount: NSInteger! = 1
-
- fileprivate var collectionView: UICollectionView!
-
- fileprivate var position: UICollectionViewScrollPosition! = .centeredHorizontally
-
- lazy fileprivate var flowLayout: UICollectionViewFlowLayout? = {
- let tempFlowLayout = UICollectionViewFlowLayout()
- tempFlowLayout.minimumLineSpacing = 0
- tempFlowLayout.scrollDirection = .horizontal
- return tempFlowLayout
- }()
-
- fileprivate var timer: Timer?
-
- fileprivate var pageControl: UIPageControl?
- fileprivate var customPageControl: UIView?
-
- fileprivate var placeHolderViewImage: UIImage! = UIImage(named: "LLCycleScrollView.bundle/llplaceholder.png")
-
- fileprivate var coverViewImage: UIImage! = UIImage.init(named: "LLCycleScrollView.bundle/llplaceholder.png")
-
- open var lldidSelectItemAtIndex: LLdidSelectItemAtIndexClosure?
- override public init(frame: CGRect) {
- super.init(frame: frame)
-
- setupMainView()
- }
-
- open class func llCycleScrollViewWithFrame(_ frame: CGRect, imageURLPaths: Array<String>? = [], titles: Array<String>? = [], didSelectItemAtIndex: LLdidSelectItemAtIndexClosure? = nil) -> LLCycleScrollView {
- let llcycleScrollView: LLCycleScrollView = LLCycleScrollView.init(frame: frame)
- if (imageURLPaths?.count)! > 0 {
- llcycleScrollView.imagePaths = imageURLPaths!
- }
- if (titles?.count)! > 0 {
- llcycleScrollView.titles = titles!
- }
- if didSelectItemAtIndex != nil {
- llcycleScrollView.lldidSelectItemAtIndex = didSelectItemAtIndex
- }
- return llcycleScrollView
- }
-
- required public init?(coder aDecoder: NSCoder) {
- super.init(coder: aDecoder)
- setupMainView()
- }
-
- private func setupMainView() {
- collectionView = UICollectionView.init(frame: self.bounds, collectionViewLayout: flowLayout!)
- collectionView.register(LLCycleScrollViewCell.self, forCellWithReuseIdentifier: identifier)
- collectionView.backgroundColor = collectionViewBackgroundColor
- collectionView.isPagingEnabled = true
- collectionView.showsHorizontalScrollIndicator = false
- collectionView.showsVerticalScrollIndicator = false
- collectionView.dataSource = self
- collectionView.delegate = self
- collectionView.scrollsToTop = false
- self.addSubview(collectionView)
- }
-
- func setupTimer() {
- timer = Timer.scheduledTimer(timeInterval: autoScrollTimeInterval as TimeInterval, target: self, selector: #selector(automaticScroll), userInfo: nil, repeats: true)
- RunLoop.main.add(timer!, forMode: .commonModes)
- }
- func invalidateTimer() {
- if timer != nil {
- timer?.invalidate()
- timer = nil
- }
- }
- func setupPageControl() {
-
- if pageControl != nil {
- pageControl?.removeFromSuperview()
- }
- if customPageControl != nil {
- customPageControl?.removeFromSuperview()
- }
- if customPageControlStyle == .none {
- pageControl = UIPageControl.init()
- pageControl?.numberOfPages = self.imagePaths.count
- }
- if customPageControlStyle == .system {
- pageControl = UIPageControl.init()
- pageControl?.pageIndicatorTintColor = pageControlTintColor
- pageControl?.currentPageIndicatorTintColor = pageControlCurrentPageColor
- pageControl?.numberOfPages = self.imagePaths.count
- self.addSubview(pageControl!)
- pageControl?.isHidden = false
- }
- if customPageControlStyle == .fill {
- customPageControl = LLFilledPageControl.init(frame: CGRect.zero)
- customPageControl?.tintColor = customPageControlTintColor
- (customPageControl as! LLFilledPageControl).indicatorPadding = customPageControlIndicatorPadding
- (customPageControl as! LLFilledPageControl).indicatorRadius = FillPageControlIndicatorRadius
- (customPageControl as! LLFilledPageControl).pageCount = self.imagePaths.count
- self.addSubview(customPageControl!)
- }
- if customPageControlStyle == .pill {
- customPageControl = LLPillPageControl.init(frame: CGRect.zero)
- (customPageControl as! LLPillPageControl).indicatorPadding = customPageControlIndicatorPadding
- (customPageControl as! LLPillPageControl).activeTint = customPageControlTintColor
- (customPageControl as! LLPillPageControl).inactiveTint = customPageControlInActiveTintColor
- (customPageControl as! LLPillPageControl).pageCount = self.imagePaths.count
- self.addSubview(customPageControl!)
- }
- if customPageControlStyle == .snake {
- customPageControl = LLSnakePageControl.init(frame: CGRect.zero)
- (customPageControl as! LLSnakePageControl).activeTint = customPageControlTintColor
- (customPageControl as! LLSnakePageControl).indicatorPadding = customPageControlIndicatorPadding
- (customPageControl as! LLSnakePageControl).indicatorRadius = FillPageControlIndicatorRadius
- (customPageControl as! LLSnakePageControl).inactiveTint = customPageControlInActiveTintColor
- (customPageControl as! LLSnakePageControl).pageCount = self.imagePaths.count
- self.addSubview(customPageControl!)
- }
- }
-
- override open func layoutSubviews() {
- super.layoutSubviews()
-
- flowLayout?.itemSize = self.frame.size
-
- if customPageControlStyle == .none || customPageControlStyle == .system {
- pageControl?.frame = CGRect.init(x: 0, y: self.ll_h-11, width: UIScreen.main.bounds.width, height: 10)
- } else {
- var y = self.ll_h-10-1
-
- if customPageControlStyle == .pill {
- y+=5
- }
- let oldFrame = customPageControl?.frame
- customPageControl?.frame = CGRect.init(x: (oldFrame?.origin.x)!, y: y, width: (oldFrame?.size.width)!, height: 10)
- }
- if collectionView.contentOffset.x == 0 && totalItemsCount > 0 {
- var targetIndex = 0
- if infiniteLoop! {
- targetIndex = totalItemsCount/2
- }
- collectionView.scrollToItem(at: IndexPath.init(item: targetIndex, section: 0), at: position, animated: false)
- }
- }
-
- @objc func automaticScroll() {
- if totalItemsCount == 0 {return}
- let targetIndex = currentIndex() + 1
- scollToIndex(targetIndex: targetIndex)
- }
- func scollToIndex(targetIndex: Int) {
- if targetIndex >= totalItemsCount {
- if infiniteLoop! {
- collectionView.scrollToItem(at: IndexPath.init(item: Int(totalItemsCount/2), section: 0), at: position, animated: false)
- }
- return
- }
- collectionView.scrollToItem(at: IndexPath.init(item: targetIndex, section: 0), at: position, animated: true)
- }
- func currentIndex() -> NSInteger {
- if collectionView.ll_w == 0 || collectionView.ll_h == 0 {
- return 0
- }
- var index = 0
- if flowLayout?.scrollDirection == UICollectionViewScrollDirection.horizontal {
- index = NSInteger(collectionView.contentOffset.x + (flowLayout?.itemSize.width)! * 0.5)/NSInteger((flowLayout?.itemSize.width)!)
- } else {
- index = NSInteger(collectionView.contentOffset.y + (flowLayout?.itemSize.height)! * 0.5)/NSInteger((flowLayout?.itemSize.height)!)
- }
- return index
- }
- func pageControlIndexWithCurrentCellIndex(index: NSInteger) -> (Int) {
- return Int(index % imagePaths.count)
- }
-
- open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
- return totalItemsCount
- }
- open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
- let cell: LLCycleScrollViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath) as! LLCycleScrollViewCell
-
- if imagePaths.count == 0 {
- cell.imageView.image = coverViewImage
- } else {
- let itemIndex = pageControlIndexWithCurrentCellIndex(index: indexPath.item)
- let imagePath = imagePaths[itemIndex]
-
- if let imageViewContentMode = imageViewContentMode {
- cell.imageView.contentMode = imageViewContentMode
- }
-
- if imagePath.hasPrefix("http") {
- cell.imageView.setImageWithNullableURL(imagePath, placeholderImage: placeHolderImage)
- } else {
- if let image = UIImage(named: imagePath) {
- cell.imageView.image = image
- } else {
- cell.imageView.image = UIImage(contentsOfFile: imagePath)
- }
- }
-
- if itemIndex <= titles.count-1 {
- cell.title = titles[itemIndex]
- } else {
- cell.title = ""
- }
- }
- return cell
- }
- open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
- if let didSelectItemAtIndexPath = lldidSelectItemAtIndex {
- didSelectItemAtIndexPath(pageControlIndexWithCurrentCellIndex(index: indexPath.item))
- }
- }
-
- open func scrollViewDidScroll(_ scrollView: UIScrollView) {
- if imagePaths.count == 0 { return }
- let indexOnPageControl = pageControlIndexWithCurrentCellIndex(index: currentIndex())
- if customPageControlStyle == .none || customPageControlStyle == .system {
- pageControl?.currentPage = indexOnPageControl
- } else {
- var progress: CGFloat = 999
-
- if scrollDirection == .horizontal {
- let currentOffsetX = scrollView.contentOffset.x - (CGFloat(totalItemsCount) * scrollView.frame.size.width) / 2
- if currentOffsetX == CGFloat(self.imagePaths.count) * scrollView.frame.size.width && infiniteLoop! {
- collectionView.scrollToItem(at: IndexPath.init(item: Int(totalItemsCount/2), section: 0), at: position, animated: false)
- }
- progress = currentOffsetX / scrollView.frame.size.width
- } else if scrollDirection == .vertical {
- let currentOffsetY = scrollView.contentOffset.y - (CGFloat(totalItemsCount) * scrollView.frame.size.height) / 2
- if currentOffsetY == CGFloat(self.imagePaths.count) * scrollView.frame.size.height && infiniteLoop! {
- collectionView.scrollToItem(at: IndexPath.init(item: Int(totalItemsCount/2), section: 0), at: position, animated: false)
- }
- progress = currentOffsetY / scrollView.frame.size.height
- }
- if progress == 999 {
- progress = CGFloat(indexOnPageControl)
- }
-
- if customPageControlStyle == .fill {
- (customPageControl as! LLFilledPageControl).progress = progress
- } else if customPageControlStyle == .pill {
- (customPageControl as! LLPillPageControl).progress = progress
- } else if customPageControlStyle == .snake {
- (customPageControl as! LLSnakePageControl).progress = progress
- }
- }
- }
- open func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
- if autoScroll! {
- invalidateTimer()
- }
- }
- open func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
- if autoScroll! {
- setupTimer()
- }
- }
- }
|