美文网首页iOS开发(OC)
iOS开发:Swift实现的轮播图、无限循环视图控件

iOS开发:Swift实现的轮播图、无限循环视图控件

作者: 吸氧 | 来源:发表于2017-01-09 14:57 被阅读760次

    Github:https://github.com/lxypeter/CYCircularScrollView

    轮播图控件实现很多,基本都思路有两种:1、使用UIScrollView + 2-3 个UIImageView的复位使用;2、使用UICollectionView。虽然网上已经有不少优秀的实现,但适逢开始学习Swift,而且这种旋转木马式的循环展现也有抽离的封装的价值,于是自己着手实现了基于UICollectionView的轮播图控件CYPicBannerScrollView及支持自定义视图的循环控件CYCircularScrollView。先上效果图:

    安装

    CocoaPods

    pod 'CYCircularScrollView'
    

    CocoaPods版本需要在1.1.0以上

    手动引入

    你也可以手动将CYCircularScrollView拷贝到项目中,但注意项目中需要同时引入Kingfisher,因为在轮播图控件** CYPicBannerScrollView**中直接使用了Kingfisher框架进行网络图片加载。

    如何使用

    轮播图控件:CYPicBannerScrollView

    1. 初始化

    CYPicBannerScrollView支持三种类型的数据源:UIImage图片链接字符串以及数据模型(Model),与之对应的有3种初始化方法。

    • UIImage类型
    convenience init(frame:CGRect, images:[Any]?, didSelected:((Int,Any)->())?)
    
    //e.g.
    let imageArray = [UIImage(named: "banner_1")!,UIImage(named: "banner_2")!,UIImage(named: "banner_3")!]
    let bannerView = CYPicBannerScrollView(frame: CGRect.zero,
                                               images:imageArray ) { (index, data) in
        //click event
    }
    
    • 图片链接字符串
    convenience init(frame:CGRect, urlStrings:[Any]?, placeholder:UIImage?, didSelected:((Int,Any)->())?)
    
    //e.g.
    let urlArray = ["www","www","www"]
    let bannerView = CYPicBannerScrollView(frame: CGRect.zero,
                                           urlStrings: urlArray,
                                           placeholder: UIImage(named: "pic_placeholder")) { (index, data) in
        //click event
    }
    
    • 数据模型(Model)
    convenience init(frame:CGRect, models:[Any]?, placeholder:UIImage?, modelImage:@escaping (Any)->(CYImageResult), didSelected:((Int,Any)->())?) 
    
    //e.g.
    let announceArray = [Announcement(title:"First Announcement",time:"2017-01-01",image:"p1"),
                        Announcement(title:"Second Announcement",time:"2017-01-02",image:"p2"),
                        Announcement(title:"Third Announcement",time:"2017-01-03",image:"p3")]
    let bannerView = CYPicBannerScrollView(frame: CGRect.zero,
                                           models: announceArray,
                                           placeholder: UIImage(named: "pic_placeholder"),
                                           modelImage: { (model) -> (CYImageResult) in
        let announcement = model as! Announcement
        return CYImageResult(data: UIImage(named: announcement.image)!, type: .image)
    }) { (index, data) in
        //click event
    }
    

    对于对象模型类型的初始化,需要在modelImage闭包中根据数据模型返回图片数据源,支持直接返回UIImage如:CYImageResult(data: UIImage(named: model.image)!, type: .image)或链接字符串如:CYImageResult(data: "http://image.com/image", type: .urlString)

    2. 自定义样式

    CYPicBannerScrollView支持以下形式的客制化

    bannerView.autoScrollInterval = 3.0 //自动翻页间隔,默认为5秒
    
    bannerView.pageControlPosition = .right //PageControl的位置,默认为center
    bannerView.pageControlOffset = UIOffset(horizontal: -10, vertical: -5) //PageControl的基于位置的偏移量
    
    //自定义PageControl的样式
    bannerView.pageControl.backgroundColor = UIColor(displayP3Red: 51/255.0, green: 51/255.0, blue: 51/255.0, alpha: 0.8)
    bannerView.pageControl.layer.cornerRadius = 8
    

    支持自定义视图的循环控件:CYCircularScrollView

    要实现自定义视图循环展示只需要四步

    • 1.继承 CYCircularScrollView
    class CYAnnounceScrollView : CYCircularScrollView
    
    • 2.覆写var cellClass:UICollectionViewCell.Type属性
    override var cellClass:UICollectionViewCell.Type {
        return CYAnnounceCell.self //循环的视图类型,需为UICollectionViewCell子类
    }
    
    • 3.覆写func configureCollectionCell(_ cell:UICollectionViewCell, data:Any) -> UICollectionViewCell方法
    override func configureCollectionCell(_ cell:UICollectionViewCell, data:Any) -> UICollectionViewCell {
            
        let announceCell = cell as! CYAnnounceCell
            
        if let announcement:Announcement = data as? Announcement{
            announceCell.announcement = announcement
        }
            
        return announceCell
    }
    
    • 4.根据需求覆写属性
    override var scrollDirection:CYScrollDirection {
        return .vertical//滚动方向,默认为.horizontal
    }
        
    override var isScrollEnabled:Bool {
        return false//是否可以手动滚动,默认为true
    }
    

    此时你就能使用你自定义的视图控件了~

    let annouceScrollView = CYAnnounceScrollView(frame: CGRect.zero, datas: self.announceArray) { (index, data) in
        //click event
    }
    

    更详尽的使用可以参照Github上的Demo。

    实现思路

    CYCircularScrollView是以UICollectionView为基础的,借助UICollectionView的可重用特性,让滚动的效果更加流畅,实现也更为简单。而为了能够实现无限循环滚动,在数据源上作了如下处理:

    无限循环
    当实际的数据源容量大于1时,UICollectionView接收的数据量加2,在前后增添各一缓冲视图,用以优化到达数据源边界时的滚动效果。同时监听UICollectionView代理下的滚动事件public func scrollViewDidScroll(_ scrollView: UIScrollView)
    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
            if self.dataArray == nil {
                return
            }
            
            var index:Float
            switch self.scrollDirection {
            case .horizontal:
                index = Float(scrollView.contentOffset.x * 1.0 / scrollView.frame.size.width)
            case .vertical:
                index = Float(scrollView.contentOffset.y * 1.0 / scrollView.frame.size.height)
            }
            
            if index < 0.25 {
                self.collectionView.scrollToItem(at: IndexPath(item: self.dataArray!.count, section: 0), at: [.top,.left], animated: false)
            }else if index >= Float(self.dataArray!.count+1) {
                self.collectionView.scrollToItem(at: IndexPath(item: 1, section: 0), at: [.top,.left], animated: false)
            }
            
            let page = self.transferIndex(Int(index))
            
            scrollToPage(page)
    }
    

    UICollectionView滚动至首项(实际数据源末项的缓冲视图)及尾项(实际数据源首项的缓冲视图)并即将展示完时,UICollectionView立即以无动画效果跳转至缓冲视图对应的实际项所在,以尽可能少的掉帧达到无限循环的效果。而当前页数的监听与刷新也在该步完成,避免了当存在UIPageControl等分页控件时当前页数的延后刷新。相比于重复复制数据源而达到无限循环效果的实现,这种方法一方面节省了内存空间,同时也避免了因为某些意外到达边界时的断层甚至崩溃。

    以上。

    相关文章

      网友评论

        本文标题:iOS开发:Swift实现的轮播图、无限循环视图控件

        本文链接:https://www.haomeiwen.com/subject/owztbttx.html