关于iOS swift3.0 UICollectionView封装引导页和轮播图

swift3.0封装引导页和轮播图

第一次写博客,文章若有不足之处,欢迎点出。

最新在写一个新的项目,用到了引导页,所以用UICollectionView封装了一下,此demo可以切换引导页和轮播图两种模式,设置代理,实现方法即可,简单便捷,参数:图片数组,模式切换,是否循环,循环速度等。不多说直接上代码,以后会继续完善。


一、代理方法

传入需要的参数,例如:

extension AppDelegate: GGGuidePageVCDataSoure{

    func getImgArrayAndSenconds() -> ([Any], Int) {

        /// 图片数组
        let arr = ["chen.jpg","hai1.jpg","mei.jpg","mei2.jpg"]
        /// 每x秒执行一次
        let senNum = 1

        return (arr,senNum)
    }

}

extension AppDelegate: GGGuidePageVCDelegate{

    /// 是否自动翻页
    func getPageBool() -> Bool {

        return true
    }

    /// 是否循环
    func getCycleBool() -> Bool {

        return true
    }

    /// page的位置
    func getPageFrame() -> PageFrameEnum{

        return PageFrameEnum.centerPage
    }

}

注:PageFrameEnum

  • 是一个枚举值:

    enum PageFrameEnum {

    case leftBottom
    case centerPage
    case rightBottom
    }

  • 简单易懂吧!

二、下面是控制器中具体的实现:

protocol GGGuidePageVCDataSoure: NSObjectProtocol{

/// 返回一个带数组和int的元组
func getImgArrayAndSenconds() -> ([Any],Int)

}

protocol GGGuidePageVCDelegate: NSObjectProtocol {

func getPageBool() -> Bool

func getCycleBool() -> Bool

func getPageFrame() -> PageFrameEnum

}

enum PageFrameEnum {

case leftBottom
case centerPage
case rightBottom

}

class GGGuidePageViewController: UICollectionViewController {

/// 图片名称数组
fileprivate lazy var imgNameArray = [Any]()
/// 翻页秒数
fileprivate lazy var pageSeconds: Int = Int()
/// 是否翻页
fileprivate lazy var pageYesAndNo: Bool = true
/// 是否循环
fileprivate lazy var cycleYesAndNo: Bool = false

var delegate: GGGuidePageVCDelegate?
var dataSoure: GGGuidePageVCDataSoure?

fileprivate var timer:DispatchSourceTimer?
fileprivate lazy var pageControl: UIPageControl = UIPageControl()
fileprivate var layout = UICollectionViewFlowLayout()


override func viewDidLoad() {
    super.viewDidLoad()

    /// 注册
    self.collectionView!.register(GGGuidePageCell.self, forCellWithReuseIdentifier:guideCell)

    /// 代理赋值
    let tuples = dataSoure?.getImgArrayAndSenconds()
    imgNameArray = tuples!.0
    pageSeconds = tuples!.1

    let pageBool = delegate?.getPageBool()
    pageYesAndNo = pageBool!

    let cycleBool = delegate?.getCycleBool()
    cycleYesAndNo = cycleBool!

    /// 设置页控制器
    configurePageController()

    /// collectionView基本设置
    basicSetting()

    /// 设置自动滚动计时器
    configureAutoScrollTimer()



}

init() {

    super.init(collectionViewLayout:layout)

}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}


func basicSetting(){

    self.collectionView?.isPagingEnabled = true
    /// 回弹效果
    self.collectionView?.bounces = true
    self.collectionView?.showsHorizontalScrollIndicator = false
    self.collectionView?.backgroundColor = UIColor.white
    /// 水平回弹
    self.collectionView?.alwaysBounceHorizontal = true

    layout.scrollDirection = UICollectionViewScrollDirection.horizontal
    layout.minimumLineSpacing = 0
    layout.minimumInteritemSpacing = 0
    layout.itemSize = UIScreen.main.bounds.size
}


/// 引导页、轮播图双模式切换
func configureAutoScrollTimer(){

    if cycleYesAndNo == true {

        /// 循环(轮播图模式)
        if pageYesAndNo == true {

            // 定义需要计时的时间
            var timeCount = 0
            // 在global线程里创建一个时间源
            timer = DispatchSource.makeTimerSource(queue:DispatchQueue.global())
            // 设定这个时间源是每秒循环一次,立即开始
            timer?.scheduleRepeating(deadline: .now() , interval: .seconds(pageSeconds))
            // 设定时间源的触发事件
            timer?.setEventHandler {
                // 每秒计时一次
                timeCount = timeCount + 1
                // 返回主线程处理一些事件,更新UI等等
                DispatchQueue.main.async {

                    let offset = CGPoint(x: CGFloat(timeCount % self.imgNameArray.count) * (self.collectionView?.bounds.width)!, y: 0)

                    self.collectionView?.setContentOffset(offset, animated: true)

                    self.pageControl.currentPage = timeCount % self.imgNameArray.count
                    debugPrint("2222")
                }
            }
            // 启动时间源
            timer?.resume()

        }else{

            debugPrint("不执行引导页翻页")

        }

    }else{

        /// 不循环(引导页模式)
        if pageYesAndNo == true {

            // 定义需要计时的时间
            var timeCount = 0
            // 在global线程里创建一个时间源
            timer = DispatchSource.makeTimerSource(queue:DispatchQueue.global())
            // 设定这个时间源是每秒循环一次,立即开始
            timer?.scheduleRepeating(deadline: .now(), interval: .seconds(pageSeconds))
            // 设定时间源的触发事件
            timer?.setEventHandler(handler: {
                // 每秒计时一次
                timeCount = timeCount + 1
                // 时间到了取消时间源
                if timeCount >= self.imgNameArray.count {
                    self.timer?.cancel()

                    DispatchQueue.main.async {

                        debugPrint("1111")
                    }

                }else{

                    // 返回主线程处理一些事件,更新UI等等
                    DispatchQueue.main.async {

                        let offset = CGPoint(x: CGFloat(timeCount) * (self.collectionView?.bounds.width)!, y: 0)

                        self.collectionView?.setContentOffset(offset, animated: true)

                        self.pageControl.currentPage = timeCount
                        debugPrint("2222")
                    }
                }
            })
            // 启动时间源
            timer?.resume()

        }else{

            debugPrint("不执行引导页翻页")

        }

    }





}


func configurePageController(){

    let pageFrame = delegate?.getPageFrame()

    switch pageFrame!{

    case .leftBottom:

        self.pageControl = UIPageControl(frame: CGRect(x:60,y: kHeight - 20, width: 120, height: 20))
        pageSetting()

    case .centerPage:

        self.pageControl = UIPageControl(frame: CGRect(x: kWidth/2-60,y: kHeight - 20, width: 120, height: 20))
        pageSetting()

    case .rightBottom:

        self.pageControl = UIPageControl(frame: CGRect(x: 300,y: kHeight - 20, width: 120, height: 20))
        pageSetting()


    }


}

func pageSetting(){

    self.pageControl.numberOfPages = imgNameArray.count
    self.pageControl.isUserInteractionEnabled = false
    // 非当前页颜色
    self.pageControl.pageIndicatorTintColor = UIColor.yellow
    // 当前页颜色
    self.pageControl.currentPageIndicatorTintColor = UIColor.red
    self.view.addSubview(self.pageControl)

}

/// btn的点击事件
func inToLoginAction(){

    APPDelegateInstance.restore(LoginViewController())

}


override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

/// MARK: UICollectionViewDataSource
extension GGGuidePageViewController{

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {

    return imgNameArray.count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: guideCell, for: indexPath as IndexPath) as! GGGuidePageCell


    cell.imgView.image = UIImage(named: imgNameArray[indexPath.row] as! String)

    cell.startButton.addTarget(self, action: #selector(inToLoginAction), for: .touchUpInside)

    cell.setIndexPath(indexPath: indexPath, count: imgNameArray.count)

    return cell
}

}

/// MARK: UICollectionViewDelegate
extension GGGuidePageViewController{

override func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {

    let imgWidth = scrollView.frame.width
    let offsetX = scrollView.contentOffset.x
    let pageIndex = offsetX / imgWidth

    self.pageControl.currentPage = Int(pageIndex)
}

/// 滑动结束方法或者正在滑动--取消时间源

}

三、结语

功能还不是很完美,但是足够普通功能的支撑,也可以给一些小伙伴们当做参考。用swift时间还不长,有些地方代码的简化还不够,写出优雅的代码是我的目标,以后会继续努力~在这之中遇到的一些坑,其中一个比较重要的就是GCD定时器的使用,先不说GCD在swift语法中的变化,在设置timer的时候记得最好是使用强引用的变量!!!!说三遍!!!!!!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值