一行iOS代码实现图片无限轮播器
最近一直在找实现图片无限轮播的方法,在网上也看了不少方法,大都不太合适,最终看到某it培训公司一位讲师用
uicollectionview:一行代码实现图片无限轮播器的方法,当然想一行代码实现轮播功能,前期还是有一些工作要做。下面就把这个方法分享给大家!
一、图片无限轮播实现效果图:
图片无限轮播.gif
二、实现原理与分析:
假设有三张图片0、1、2,想要实现无限轮播,我们可以将uicollectionview的cell个数设为图片的个数 x 3,也就是把三张图片重复添加到9个cell中,可以把无限轮播分解成五种特殊的状态(五个临界点),轮播开始时为初始状态,在定时器的作用下依次滚动到最后一个cell,此时为右临界状态显示的是第2张图片,若想继续无缝滚动到第0图片,我们可以偷偷的将collectionview滚动到第三个cell上,可以看第四幅转态图此时显示的依然是第2张图片,这样再次滚动就是第0张图,这样就实现了cell向左滚动的无限循环轮播;向右滚动的原理一样,就是第三幅图到第五幅图的变化。
初始界状态.png
右临界状态.png
左临界状态.png
paste_image.png
paste_image.png
三、代码:
类文件.png
- jfweaktimertargetobject继承自nsobject
- jfloopview继承自uiview
- jfloopviewcell继承自uicollectionviewcell
- jfloopviewlayout继承自uicollectionviewflowlayout
- jfmainviewcontroller继承自uiviewcontroller
jfweaktimertargetobject重写定时器nstimer的+ (nstimer *)scheduledtimerwithtimeinterval:(nstimeinterval)ti target:(id)atarget selector:(sel)aselector userinfo:(nullable id)userinfo repeats:(bool)yesorno;类方法的目的是:避免当定时器强引用jfloopview类,jfloopview无法被释放的问题。
jfweaktimertargetobject.h文件
#import <foundation/foundation.h> @interface jfweaktimertargetobject : nsobject + (nstimer *)scheduledtimerwithtimeinterval:(nstimeinterval)ti target:(id)atarget selector:(sel)aselector userinfo:(nullable id)userinfo repeats:(bool)yesorno; @end
jfweaktimertargetobject.m文件
#import "jfweaktimertargetobject.h" @interface jfweaktimertargetobject () @property (nonatomic, weak) id target; @property (nonatomic, assign) sel selector; @end @implementation jfweaktimertargetobject + (nstimer *)scheduledtimerwithtimeinterval:(nstimeinterval)ti target:(id)atarget selector:(sel)aselector userinfo:(nullable id)userinfo repeats:(bool)yesorno { //创建当前类对象 jfweaktimertargetobject *object = [[jfweaktimertargetobject alloc] init]; object.target = atarget; object.selector = aselector; return [nstimer scheduledtimerwithtimeinterval:ti target:object selector:@selector(fire:) userinfo:userinfo repeats:yesorno]; } - (void)fire:(id)obj { [self.target performselector:self.selector withobject:obj]; } @end
jfloopview.h文件
#import <uikit/uikit.h> @interface jfloopview : uiview //jfloopview初始化方法 - (instancetype)initwithimagearray:(nsarray *)imagearray; @end
jfloopview.m文件
#import "jfloopview.h" #import "jfloopviewlayout.h" #import "jfloopviewcell.h" #import "jfweaktimertargetobject.h" @interface jfloopview () <uicollectionviewdelegate, uicollectionviewdatasource> @property (nonatomic, strong) uicollectionview *collectionview; @property (nonatomic, strong) uipagecontrol *pagecontrol; @property (nonatomic, strong) nsarray *imagearray; @property (nonatomic, weak) nstimer *timer; @end static nsstring *id = @"loopviewcell"; @implementation jfloopview - (instancetype)initwithimagearray:(nsarray *)imagearray { if (self = [super init]) { uicollectionview *collectionview = [[uicollectionview alloc] initwithframe:cgrectzero collectionviewlayout:[[jfloopviewlayout alloc] init]]; [collectionview registerclass:[jfloopviewcell class] forcellwithreuseidentifier:id]; collectionview.datasource = self; collectionview.delegate = self; [self addsubview:collectionview]; self.collectionview = collectionview; self.imagearray = imagearray; //添加分页器 [self addsubview:self.pagecontrol]; //回到主线程刷新ui dispatch_async(dispatch_get_main_queue(), ^{ //设置滚动的初始状态在 [self.collectionview scrolltoitematindexpath:[nsindexpath indexpathforitem:self.imagearray.count insection:0] atscrollposition:uicollectionviewscrollpositionleft animated:no]; //添加定时器 [self addtimer]; }); } return self; } /// 懒加载pagecontrol - (uipagecontrol *)pagecontrol { if (!_pagecontrol) { _pagecontrol = [[uipagecontrol alloc] initwithframe:cgrectmake(0, 220, 0, 30)]; _pagecontrol.numberofpages = self.imagearray.count; _pagecontrol.pageindicatortintcolor = [uicolor orangecolor]; _pagecontrol.currentpageindicatortintcolor = [uicolor purplecolor]; } return _pagecontrol; } #pragma mark --- uicollectionviewdatasource 数据源方法 - (nsinteger)collectionview:(uicollectionview *)collectionview numberofitemsinsection:(nsinteger)section { return self.imagearray.count * 3; } - (uicollectionviewcell *)collectionview:(uicollectionview *)collectionview cellforitematindexpath:(nsindexpath *)indexpath { jfloopviewcell *cell = [collectionview dequeuereusablecellwithreuseidentifier:id forindexpath:indexpath]; cell.imagename = self.imagearray[indexpath.item % self.imagearray.count]; return cell; } #pragma mark ---- uicollectionviewdelegate /// 滚动完毕就会调用(如果不是人为拖拽scrollview导致滚动完毕,才会调用这个方法) - (void)scrollviewdidendscrollinganimation:(uiscrollview *)scrollview { [self scrollviewdidenddecelerating:scrollview]; } /// 当滚动减速时调用 - (void)scrollviewdidenddecelerating:(uiscrollview *)scrollview { cgfloat offsetx = scrollview.contentoffset.x; nsinteger page = offsetx / scrollview.bounds.size.width; //手动滚动到左边临界状态 if (page == 0) { page = self.imagearray.count; self.collectionview.contentoffset = cgpointmake(page * scrollview.frame.size.width, 0); //滚动到右临界状态 }else if (page == [self.collectionview numberofitemsinsection:0] - 1) { page = self.imagearray.count - 1; self.collectionview.contentoffset = cgpointmake(page * scrollview.frame.size.width, 0); } //设置uipagecontrol当前页 nsinteger currentpage = page % self.imagearray.count; self.pagecontrol.currentpage =currentpage; //添加定时器 [self addtimer]; } ///手指开始拖动时调用 - (void)scrollviewwillbegindragging:(uiscrollview *)scrollview { //移除定时器 [self removetimer]; } /// 添加定时器 - (void)addtimer { if (self.timer) return; self.timer = [jfweaktimertargetobject scheduledtimerwithtimeinterval:1.5 target:self selector:@selector(nextimage) userinfo:nil repeats:yes]; [[nsrunloop currentrunloop] addtimer:self.timer formode:nsrunloopcommonmodes]; } /// 移除定时器 - (void)removetimer { [self.timer invalidate]; self.timer = nil; } /// 切换到下一张图片 - (void)nextimage { cgfloat offsetx = self.collectionview.contentoffset.x; nsinteger page = offsetx / self.collectionview.bounds.size.width; [self.collectionview setcontentoffset:cgpointmake((page + 1) * self.collectionview.bounds.size.width, 0) animated:yes]; } - (void)layoutsubviews { [super layoutsubviews]; self.collectionview.frame = self.bounds; } - (void)dealloc { [self removetimer]; } @end
jfloopviewcell.h文件
#import <uikit/uikit.h> @interface jfloopviewcell : uicollectionviewcell @property (nonatomic, copy) nsstring *imagename; @end
jfloopviewcell.m文件
#import "jfloopviewcell.h" @interface jfloopviewcell () @property (nonatomic, weak) uiimageview *iconview; @end @implementation jfloopviewcell - (instancetype)initwithframe:(cgrect)frame { if (self = [super initwithframe:frame]) { uiimageview *iconview = [[uiimageview alloc] init]; [self addsubview:iconview]; self.iconview = iconview; } return self; } - (void)setimagename:(nsstring *)imagename { _imagename = imagename; self.iconview.image = [uiimage imagenamed:imagename]; } - (void)layoutsubviews { [super layoutsubviews]; self.iconview.frame = self.bounds; } @end
jfloopviewlayout.h文件
#import <uikit/uikit.h> @interface jfloopviewlayout : uicollectionviewflowlayout @end
jfloopviewlayout.m文件
#import "jfloopviewlayout.h" @implementation jfloopviewlayout /// 准备布局 - (void)preparelayout { [super preparelayout]; //设置item尺寸 self.itemsize = self.collectionview.frame.size; //设置滚动方向 self.scrolldirection = uicollectionviewscrolldirectionhorizontal; //设置分页 self.collectionview.pagingenabled = yes; //设置最小间距 self.minimumlinespacing = 0; self.minimuminteritemspacing = 0; //隐藏水平滚动条 self.collectionview.showshorizontalscrollindicator = no; } @end
jfmainviewcontroller.h文件
#import <uikit/uikit.h> @interface jfmainviewcontroller : uiviewcontroller @end
jfmainviewcontroller.m文件
#import "jfmainviewcontroller.h" #import "jfloopview.h" @interface jfmainviewcontroller () @property (nonatomic, strong) jfloopview *loopview; @end @implementation jfmainviewcontroller - (void)viewdidload { [super viewdidload]; //关闭自动调整滚动视图 self.automaticallyadjustsscrollviewinsets = no; } - (void)viewwillappear:(bool)animated { [super viewwillappear:animated]; self.navigationcontroller.navigationbar.hidden = yes; } - (void)loadview { [super loadview]; //设置图片数据 nsarray *imagearray = @[@"srcoll_01",@"srcoll_02",@"srcoll_03"]; //此行代码实现无限轮播 _loopview = [[jfloopview alloc] initwithimagearray:imagearray]; //设置loopview的frame _loopview.frame = cgrectmake(0, 0, [uiscreen mainscreen].bounds.size.width, 250); [self.view addsubview:self.loopview]; } - (void)didreceivememorywarning { [super didreceivememorywarning]; // dispose of any resources that can be recreated. } @end
注意:如果你的控制器有uinavigationbar,且隐藏了navigationbar,一定要记得设置self.automaticallyadjustsscrollviewinsets = no; automaticallyadjustsscrollviewinsets是干嘛的呢?简单点说就是automaticallyadjustsscrollviewinsets根据所在界面的status bar、navigationbar、与tabbar的高度,自动调整scrollview的 inset,设置为no,不让viewcontroller调整,我们自己修改布局即可。如果不设置为no就可能出现下面的情况,自动滚动和拖动的时候imageview的位置会变化。
图片无限轮播bug展示.gif
四、总结:
1、实现无限轮播器的主要控件是uicollectionview和uipagecontrol,
2、封装好工具类以后再使用时一行_loopview = [[jfloopview alloc] initwithimagearray:imagearray];代码,然后设置frame就可以复用无限轮播器。
3、合理切换图片和图片排列的方法,加上恰当地使用uicollectionview提供的代理方法就可以完美的实现无限轮播器。
写在最后:
下一篇文章讲用uicollectionview实现电商app首页的方法:
电商app的首页展示.gif
如果你有好的方法敬请分享,感谢你的阅读!欢迎关注和评论!
源码地址:链接: https://pan.baidu.com/s/1nv5fqzj 密码: qz3u
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。