iOS swift版本无限滚动轮播图

之前写过oc版本的无限滚动轮播图,现在来一个swift版本全部使用snapKit布局,数字还是pageConrrol样式可选

enum typeStyle: Int {
    case pageControl
    case label
}

效果图:

代码:

//
//  TYCarouselView.swift
//  hxquan-swift
//
//  Created by Tiny on 2018/11/12.
//  Copyright © 2018年 hxq. All rights reserved.
//  轮播图

import UIKit

let ImgPlaceHolder = UIImage(named: "picture")

enum typeStyle: Int {
    case pageControl
    case label
}

class TYCarouselCell: UICollectionViewCell {
    
    var url: String = ""{
        didSet{
            let cacheImg = SDImageCache.shared().imageFromDiskCache(forKey: url)
            imgView.contentMode = .center
            imgView.sd_setImage(with: URL(string: url),placeholderImage:cacheImg ?? ImgPlaceHolder) { [unowned self] (image, error, _, _) in
                if image != nil && error == nil{
                    self.imgView.contentMode = .scaleAspectFill
                }
            }
        }
    }
    
    lazy var imgView: UIImageView = {
        let imgView = UIImageView()
        imgView.layer.masksToBounds = true
        imgView.contentMode = .center
        imgView.image = ImgPlaceHolder
        return imgView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        setupUI()
    }
    
    func setupUI(){
        contentView.addSubview(imgView)
        
        imgView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
    }
}

class TYCarouselView: UIView {
    
    var style: typeStyle = .pageControl{
        didSet{
            if style == .pageControl{
                if pageControl.superview == nil{
                    addSubview(pageControl)
                    pageControl.snp.makeConstraints { (make) in
                        make.centerX.equalToSuperview()
                        make.bottom.equalToSuperview().offset(-10)
                    }
                }
                if label.superview != nil{
                    label.removeFromSuperview()
                }
            }else{
                if label.superview == nil{
                    addSubview(label)
                    label.snp.makeConstraints { (make) in
                        make.right.equalToSuperview().offset(-20)
                        make.bottom.equalToSuperview().offset(-20)
                    }
                }
                if pageControl.superview != nil{
                    pageControl.removeFromSuperview()
                }
            }
        }
    }
    
    /// 定时器是否开启
    var isTimerEnable = true
    
    fileprivate let maxsection: Int = 100
    
    /// 滚动间隔
    public let scroInterval: TimeInterval = 4
    
    private var selectonBlock: ((Int)->Void)?
    
    public var images = [String]() {
        didSet{
            //重写images set方法
            //更新数据源
            collectionView.reloadData()
            if style == .pageControl {
                pageControl.numberOfPages = images.count
            }else{
                if oldValue.count == 0{
                    label.attributedText = labelAttrText(1)
                }
                label.isHidden = images.count == 0
            }
            if isTimerEnable && !images.isEmpty{
                timerStart()
            }
        }
    }
    
    lazy var pageControl: UIPageControl = {
        let pageControl = UIPageControl()
        pageControl.sizeToFit()
        return pageControl
    }()
    
    lazy var label: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 12)
        label.textColor = UIColor.white
        label.attributedText = labelAttrText(0)
        label.isHidden = true
        return label
    }()
    
    fileprivate lazy var collectionView: UICollectionView = { [unowned self] in
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumLineSpacing = 0
        layout.minimumInteritemSpacing = 0
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.backgroundColor = UIColor.white
        collectionView.showsVerticalScrollIndicator = false
        collectionView.showsHorizontalScrollIndicator = false
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.isPagingEnabled = true
        collectionView.register(TYCarouselCell.self, forCellWithReuseIdentifier: "TYCarouselCell")
        
        return collectionView
        }()
    
    fileprivate lazy var timer: Timer = { [unowned self] in
        let timer = Timer(timeInterval: scroInterval, target: self, selector: #selector(timerInterval), userInfo: nil, repeats: true)
        RunLoop.current.add(timer, forMode: .common)
        return timer
    }()
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    convenience init(frame: CGRect,selectonBlock: ((Int)->Void)?){
        self.init(frame: frame)
        self.selectonBlock = selectonBlock
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    
    private func setupUI(){
        addSubview(collectionView)
        collectionView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
        
        addSubview(pageControl)
        pageControl.snp.makeConstraints { (make) in
            make.bottom.equalToSuperview().offset(-10)
            make.centerX.equalToSuperview()
        }
    }
    
    @objc func timerInterval(){
        //取当前idnexPath
        if let currentIndexPath = collectionView.indexPathsForVisibleItems.last{
            //先让collectionViev滚动到中间
            let currentIndexPathReset = IndexPath(row: currentIndexPath.row, section: maxsection/2)
            collectionView.scrollToItem(at: currentIndexPathReset, at: .left, animated: false)
            
            //让当前indexPath.row++
            var row = currentIndexPath.row + 1
            var nextsection = currentIndexPathReset.section
            if row >= images.count{
                row = 0
                nextsection = nextsection + 1
            }
            if style == .pageControl {
                pageControl.currentPage = row
            }else{
                label.attributedText = labelAttrText(row+1)
            }
            let nextIndexPath = IndexPath(row: row, section:nextsection)
            collectionView.scrollToItem(at: nextIndexPath, at: .left, animated: true)
        }
    }
    
    private func timerStart(){
        if !timer.isValid {
            timer.fire()
        }
    }
    
    private func timerPause(){
        if timer.isValid {
            timer.invalidate()
        }
    }
    
    private func labelAttrText(_ index: Int) -> NSAttributedString{
        let lf = "(index)"
        let rt = "(images.count)"
        let str = lf + "/" + rt
        let attr = NSMutableAttributedString(string: str)
        attr.setAttributes([NSAttributedString.Key.foregroundColor : UIColor.red], range: NSRange(location: 0, length: 1))
        return attr
    }
}

extension TYCarouselView: UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout{
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return maxsection
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return images.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "TYCarouselCell", for: indexPath) as! TYCarouselCell
        cell.url = images[indexPath.row]
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize( self.bounds.size.width, height: self.bounds.size.height)
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        selectonBlock?(indexPath.row)
    }
    
    //结束滚动
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let index = Int(scrollView.contentOffset.x / self.bounds.size.width + 0.5) % images.count
        if style == .pageControl {
            pageControl.currentPage = index
        }else{
            label.attributedText = labelAttrText(index+1)
        }
        if(isTimerEnable){
            //定时器启动
            if timer.isValid {
                timer.fireDate = Date.init(timeIntervalSinceNow: scroInterval)
            }
        }
    }
    
    //拖动
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
        if isTimerEnable{
            //定时器暂停
            if timer.isValid {
                timer.fireDate = Date.distantFuture
            }
        }
    }
}

使用方法:

    lazy var carouselView: TYCarouselView = { [unowned self] in
        let carouselView = TYCarouselView(frame: .zero, selectonBlock: { (index) in
            print("(index)")
        })
        carouselView.style = .label
        carouselView.layer.masksToBounds = true
        carouselView.layer.cornerRadius = 10
        return carouselView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
            //添加到父视图
        view.addSubview(carouselView)
        //设置约束
        carouselView.snp.makeConstraints { (make) in
            make.left.equalTo(15)
            make.right.equalTo(-15)
            make.top.equalTo(10)
            make.height.equalTo(170)
        }
        //设置数据源
        var imgs = [String]()
        for _ in 0..<5{
            imgs.append("图url")
        }
        self.carouselView.images = imgs
    }
原文地址:https://www.cnblogs.com/qqcc1388/p/10000607.html