Swift简单的轮播图
//
// CycleView.swift
//
import UIKit
import SDWebImage
let CycleViewCellIdentifier: String = "CycleViewCellIdentifier"
let width = (UIScreen.main.bounds.size.width)
let height = (UIScreen.main.bounds.size.width)
let MaxSection = 100
// 协议
protocol CycleViewDelegate {
func didSelectIndexCollectionViewCell(index: Int)->Void
}
class CycleView: UIView {
//MARK: -属性列表
/// 图片数组
var imageArray: [String]?
{
didSet{
pageControl.isHidden = (imageArray?.count == 1)
pageControl.numberOfPages = (imageArray?.count)!
collectionView.reloadData()
startTimer()
}
}
/// title数组
var titleArray: [String]?
{
didSet{
collectionView.reloadData()
startTimer()
}
}
/// 轮播时间
var time: TimeInterval = 2
{
didSet{
startTimer()
}
}
var timer: Timer?
var delegate: CycleViewDelegate?
//MARK: -初始化
override init(frame: CGRect) {
super.init(frame: frame)
// 初始化UI
setupUI(frame: frame)
}
override func layoutSubviews() {
super.layoutSubviews()
// 1.有导航控制器时,会默认在scrollview上方添加64的内边距,这里强制设置为0
collectionView.contentInset = UIEdgeInsets.zero
collectionView.scrollToItem(at: IndexPath(item: 0, section: MaxSection/2), at: .left, animated: false)
// 2.设置subView的frame
collectionView.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
pageControl.frame = CGRect(x: 0, y: 0, width: self.frame.size.width / 2, height: 15)
pageControl.center = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height - 15)
}
//MARK: -Function
/// 初始化UI
private func setupUI(frame:CGRect){
// 1.添加子控件
addSubview(collectionView)
addSubview(pageControl)
}
/// 开始定时器
func startTimer(){
//如果只有一张图片,则直接返回,不开启定时器
if imageArray?.count == 1 {
return
}
//如果定时器已开启,先停止再重新开启
if (timer != nil) {
endTimer()
}
timer = Timer.init(timeInterval: time, target: self, selector: #selector(nextPageView), userInfo: nil, repeats: true)
RunLoop.current.add(timer!, forMode: RunLoopMode.commonModes)
}
/// 停止定时器
func endTimer(){
timer?.invalidate()
timer = nil
}
//MARK: -进入下一页
func nextPageView()
{
//获取当前indexPath
let currentIndexPath = collectionView.indexPathsForVisibleItems.last!
//获取中间那一组的indexPath
let middleIndexPath = IndexPath(item: currentIndexPath.item, section: MaxSection/2)
//滚动到中间那一组
collectionView.scrollToItem(at: middleIndexPath, at: .left, animated: false)
var nextItem = middleIndexPath.item + 1
var nextSection = middleIndexPath.section
if nextItem == imageArray?.count {
nextItem = 0
nextSection += 1
}
collectionView.scrollToItem(at: IndexPath(item: nextItem, section: nextSection), at: .left, animated: true)
}
//MARK: -懒加载
fileprivate lazy var collectionView: UICollectionView = {
print(self.frame)
let flowLayout = CycleScrollViewFlowLayout()
flowLayout.itemSize = CGSize(width: self.frame.size.width, height: self.frame.size.height)
let clv = UICollectionView(frame: CGRect.zero, collectionViewLayout: flowLayout)
clv.register(CycleViewCell.self, forCellWithReuseIdentifier: CycleViewCellIdentifier)
clv.dataSource = self
clv.delegate = self
return clv
}()
fileprivate lazy var pageControl: UIPageControl = {
let pc = UIPageControl()
pc.isUserInteractionEnabled = false
return pc
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//MARK: -
extension CycleView: UICollectionViewDelegate,UICollectionViewDataSource
{
//MARK: -UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return MaxSection
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return imageArray?.count ?? 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CycleViewCellIdentifier, for: indexPath) as! CycleViewCell
cell.dict = ["labelText":titleArray?.count == nil ? "labelText" : (titleArray?[indexPath.row])!,
"imageStr" :(imageArray?[indexPath.row])!]
return cell
}
//MARK: -UICollectionViewDelegate
// 点击轮播图片
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
self.delegate?.didSelectIndexCollectionViewCell(index: indexPath.row)
}
//MARK: -UIScrollViewDelegate
// 停止拖拽的时候开始执行
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
endTimer()
}
// 停止拖拽的时候开始执行
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
startTimer()
}
// 手指离开减速停止的时候开始执行
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
//暂不做处理
}
//在这个方法中算出当前页数
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let page = Int((scrollView.contentOffset.x + (collectionView.bounds.width) * 0.5) / (collectionView.bounds.width))
let currentPage = page % (imageArray?.count)!
pageControl.currentPage = currentPage
//起始位置和最终位置的切换
if scrollView.contentOffset.x >= (CGFloat)((imageArray?.count)! * MaxSection - 3) * width || scrollView.contentOffset.x <= 2{
collectionView.scrollToItem(at: IndexPath(item: pageControl.currentPage, section: MaxSection/2), at: .left, animated: false)
}
}
}
//MARK: -
class CycleScrollViewFlowLayout:UICollectionViewFlowLayout
{
override func prepare() {
// 1.设置layout布局
minimumInteritemSpacing = 0
minimumLineSpacing = 0
scrollDirection = UICollectionViewScrollDirection.horizontal
// 2.设置collectionView的属性
collectionView?.isPagingEnabled = true
collectionView?.showsHorizontalScrollIndicator = false
collectionView?.showsVerticalScrollIndicator = false
}
}
//MARK: -
let CycleViewCellBottomViewHeight: CGFloat = 30
let CycleViewCellMargin: CGFloat = 10
class CycleViewCell: UICollectionViewCell {
var dict: [String:String]?
{
didSet{
iconImageView.sd_setImage(with: NSURL(string: (dict!["imageStr"])!) as URL?, placeholderImage: UIImage(named: "banner"))
if dict?["labelText"] == "labelText" {
titleLabel.isHidden = true
bottomView.isHidden = true
}
else
{
titleLabel.text = dict?["labelText"]
titleLabel.isHidden = false
bottomView.isHidden = false
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
// 1.添加子控件
contentView.addSubview(iconImageView)
iconImageView.addSubview(bottomView)
bottomView.addSubview(titleLabel)
// 2.布局子控件
iconImageView.frame = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
bottomView.frame = CGRect(x: 0, y: frame.size.height - CycleViewCellBottomViewHeight, width: height, height: CycleViewCellBottomViewHeight)
titleLabel.frame = CGRect(x: CycleViewCellMargin, y: 0, width: height - 2*CycleViewCellMargin, height: CycleViewCellBottomViewHeight)
}
//MARK: -懒加载
private lazy var iconImageView: UIImageView = {
let img = UIImageView()
return img
}()
private lazy var bottomView: UIView = {
let view = UIView()
view.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0.5)
return view
}()
private lazy var titleLabel: UILabel = {
let label = UILabel()
label.textColor = UIColor.white
label.font = UIFont.systemFont(ofSize: 14)
return label
}()
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
效果图
如果有什么问题请大家指正,谢谢!
推荐轮播1 - SDCycleScrollView
推荐轮播2 - XRCarouselView
推荐轮播2 - 创建轮播图的四种思路