Swift - UIScrollView 循环滚动

之前使用Objective-C 封装过,但是目前项目使用swift,对此对又封装一个控件,便于以后应用,重复写。
功能:

  • 使用Swift4.0
  • 使用三个UIImageView实现无限循环
  • 支持一张或多张图片
  • 单张不显示pageController,不可滑动
  • 目前使用UIImage,提供简单版本,自己可以根据需求改动定制,如使用SDWebImage缓存加载等

控件封装

import UIKit
public protocol CycleScrollViewDelegate{
    func selectCycleScrollViewPage(idx:Int);
}

class CycleScrollView: JDView {
    var imageArr: Array = []  {
        willSet {
            self.currentPage = 0
            self.pageControl.numberOfPages = newValue.count
            self.pageControl.currentPage = 0
            if newValue.count > 1 {
                self.pageControl.isHidden = false
                self.scrollview.isScrollEnabled = true
            }
            else {
                self.pageControl.isHidden = true
                self.scrollview.isScrollEnabled = false
            }
        }
        didSet {
            self.updateImageData()
        }
    }
    var autoShow: Bool = false {
        didSet {
            if self.autoShow {
                self.startTimer()
            } else {
                self.startTimer()
            }
        }
    }
    var delegate: CycleScrollViewDelegate? = nil
    
    var currentPage: Int = 0
    
    lazy var autoTimer: Timer? = {
        let timer = Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
        return timer
    }()
    lazy var imageVArr: Array = {
        var arr: Array = []
        for i in 0...2 {
            let v = UIImageView()
            arr.append(v)
        }
        return arr
    }()
    lazy var scrollview: UIScrollView = {
        let v = UIScrollView()
        v.showsVerticalScrollIndicator = false
        v.showsHorizontalScrollIndicator = false
        v.isPagingEnabled = true
        v.bounces = false
        v.delegate = self
        v.addGestureRecognizer(self.tap)
        for i in 0...2 {
            let imageV = self.imageVArr[i]
            v.addSubview(imageV)
        }
        return v
    }()
    lazy var pageControl: UIPageControl = {
        let pc = UIPageControl()
        pc.isUserInteractionEnabled = false
        pc.pageIndicatorTintColor = color_text_lightGray
        pc.currentPageIndicatorTintColor = color_nav_red
        return pc
    }()
    
    lazy var tap: UITapGestureRecognizer = {
        let tap = UITapGestureRecognizer.init(target: self, action: #selector(tapAction(_:)))
        tap.numberOfTapsRequired = 1
        tap.numberOfTouchesRequired = 1
        return tap
    }()
    
    override init() {
        super.init()
        self.addSubview(self.scrollview)
        self.addSubview(self.pageControl)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.scrollview.snp.makeConstraints { (make) in
            make.top.right.bottom.left.equalToSuperview()
        }
        self.pageControl.snp.makeConstraints { (make) in
            make.bottom.left.right.equalToSuperview()
            make.height.equalTo(20.0)
        }
        
        let w = self.scrollview.frame.size.width
        let h = self.scrollview.frame.size.height
        
        self.scrollview.contentSize = CGSize(width: w * 3, height: h)

        for i in 0...2 {
            let imageV = self.imageVArr[i]
            imageV.frame = CGRect(x: CGFloat(i) * w, y: 0, width: w, height: h)
        }
    }
    
    deinit {
        self.autoTimer?.invalidate()
        self.autoTimer = nil
    }
    /*
    // Only override draw() if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    override func draw(_ rect: CGRect) {
        // Drawing code
    }
    */

}

extension CycleScrollView {
    @objc func tapAction(_ tap: UITapGestureRecognizer) {
        if let del = self.delegate {
            del.selectCycleScrollViewPage(idx: self.currentPage)
        }
    }
    @objc func timerAction() {
        if self.currentPage == self.imageArr.count - 1{
            self.currentPage = 0
        }else{
            self.currentPage += 1
        }
        self.updateImageData()
    }
    
    func stopTimer() {
        if self.autoShow {
            self.autoTimer?.fireDate = Date.distantFuture
        }
    }
    func startTimer() {
        if self.autoShow {
            self.autoTimer?.fireDate = Date.distantPast
        }
    }
    
    func updateImageData() {
        let imageV0 = self.imageVArr[0]
        let imageV1 = self.imageVArr[1]
        let imageV2 = self.imageVArr[2]
        
        if self.imageArr.count == 1 {
            imageV0.image = self.imageArr[0]
            imageV1.image = self.imageArr[0]
            imageV2.image = self.imageArr[0]
        }
        else {
            if self.currentPage == 0 {
                imageV0.image = self.imageArr.last
                imageV1.image = self.imageArr[self.currentPage]
                imageV2.image = self.imageArr[self.currentPage + 1]
            } else if currentPage == self.imageArr.count - 1 {
                imageV0.image = self.imageArr[self.currentPage - 1]
                imageV1.image = self.imageArr[self.currentPage]
                imageV2.image = self.imageArr.first
            }
            else {
                imageV0.image = self.imageArr[self.currentPage - 1]
                imageV1.image = self.imageArr[self.currentPage]
                imageV2.image = self.imageArr[self.currentPage + 1]
            }
            self.pageControl.currentPage = currentPage
            self.scrollview.contentOffset = CGPoint(x: self.frame.size.width, y: 0)
        }
    }
    
    func endScrollMethod(_ ratio: CGFloat) {
        if ratio <= 0.7 {
            if self.currentPage - 1 < 0 {
                self.currentPage = self.imageArr.count - 1
            } else {
                self.currentPage -= 1
            }
        }
        if ratio >= 1.3 {
            if self.currentPage == self.imageArr.count - 1 {
                self.currentPage = 0
            }
            else {
                self.currentPage += 1
            }
        }
        self.updateImageData()
        self.startTimer()
    }
}
extension CycleScrollView: UIScrollViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let ratio = scrollView.contentOffset.x/self.frame.size.width
        self.endScrollMethod(ratio)
    }
    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate {
            let ratio = scrollView.contentOffset.x/self.frame.size.width
            self.endScrollMethod(ratio)
        }
    }
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        self.stopTimer()
    }
    
}

控件应用

let cycleScrollView = CycleScrollView.init()
cycleScrollView.imageArr = [UIImage(named: "image01")] as! Array//, UIImage(named: "image02"), UIImage(named: "image03"), UIImage(named: "image04")
cell?.cycleScrollView.autoShow = true

参考文章

你可能感兴趣的:(Swift - UIScrollView 循环滚动)