效果图
原理:给collectionView设置多组一样的数据,默认展示中间的那一组.当滚动到上一组或者下一组的时候采用无动画的方式滚动到最中间的那一组.这样就实现了视图的无限轮播.
class MCCycleView: UIView, UICollectionViewDelegate, UICollectionViewDataSource {
private var collectionView: UICollectionView!
private var pageControl: UIPageControl!
private var timer: Timer?
lazy var picArr: [UIImage] = {
return [UIImage(named: "1")!,
UIImage(named: "2")!,
UIImage(named: "3")!,
UIImage(named: "4")!,
UIImage(named: "5")!]
}()
private let CycleReuseIdentifier = "CycleReuseIdentifier"
//组数 多少组都可以最少三组
private let MaxSections = 3
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
private func setup() {
//设置flowLayout属性
let flowLayout = UICollectionViewFlowLayout()
flowLayout.itemSize = CGSize(width: UIScreen.main.bounds.width, height: 150)
flowLayout.minimumLineSpacing = 0
flowLayout.minimumInteritemSpacing = 0
flowLayout.scrollDirection = .horizontal
collectionView = UICollectionView(frame: frame, collectionViewLayout: flowLayout)
collectionView.isPagingEnabled = true
collectionView.register(MCCycleCell.self, forCellWithReuseIdentifier: CycleReuseIdentifier)
collectionView.delegate = self
collectionView.dataSource = self
//默认滚动到中间的那一组
collectionView.scrollToItem(at: IndexPath(item: 0, section: MaxSections / 2), at: .left, animated: false)
addSubview(collectionView)
pageControl = UIPageControl()
pageControl.numberOfPages = picArr.count
pageControl.currentPageIndicatorTintColor = UIColor.orange
addSubview(pageControl)
//添加定时器
addTimer()
//设置collectionView和pageControl的约束
collectionView.snp.makeConstraints { (make) in
make.top.equalTo(self.snp.top)
make.left.equalTo(self.snp.left)
make.bottom.equalTo(self.snp.bottom)
make.right.equalTo(self.snp.right)
}
pageControl.snp.makeConstraints { (make) in
make.right.equalTo(self.snp.right).offset(-10)
make.bottom.equalTo(self.snp.bottom).offset(-10)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return MaxSections
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return picArr.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CycleReuseIdentifier, for: indexPath) as! MCCycleCell
cell.img = picArr[indexPath.item]
return cell
}
//在这个方法中算出当前页数
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let page = Int((scrollView.contentOffset.x + (collectionView?.bounds.width)! * 0.5) / (collectionView?.bounds.width)!)
let currentPage = page % picArr.count
pageControl?.currentPage = currentPage
}
//在开始拖拽的时候移除定时器
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
timer?.invalidate()
timer = nil
}
//结束拖拽的时候重新添加定时器
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
addTimer()
}
//手动滑动
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
collectionView.scrollToItem(at: IndexPath(item: pageControl.currentPage, section: 1), at: .left, animated: false)
}
private func addTimer() {
timer = Timer(timeInterval: 3, target: self, selector: #selector(nextImage), userInfo: nil, repeats: true)
RunLoop.current.add(timer!, forMode: .commonModes)
}
@objc private func nextImage() {
//获取当前indexPath
let currentIndexPath = collectionView.indexPathsForVisibleItems.last!
//获取中间那一组的indexPath
let middleIndexPath = IndexPath(item: currentIndexPath.item, section: 1)
//滚动到中间那一组
collectionView.scrollToItem(at: middleIndexPath, at: .left, animated: false)
var nextItem = middleIndexPath.item + 1
var nextSection = middleIndexPath.section
if nextItem == picArr.count {
nextItem = 0
nextSection += 1
}
collectionView.scrollToItem(at: IndexPath(item: nextItem, section: nextSection), at: .left, animated: true)
}
}
class MCCycleCell: UICollectionViewCell {
private var ImgView: UIImageView = UIImageView()
var img: UIImage? {
didSet {
ImgView.image = img
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(ImgView)
ImgView.snp.makeConstraints { (make) in
make.top.equalTo(self.snp.top)
make.left.equalTo(self.snp.left)
make.bottom.equalTo(self.snp.bottom)
make.right.equalTo(self.snp.right)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}