服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - IOS - 一行iOS代码实现图片无限轮播器

一行iOS代码实现图片无限轮播器

2021-03-17 15:40zhifenx IOS

一行iOS代码实现图片无限轮播器的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

最近一直在找实现图片无限轮播的方法,在网上也看了不少方法,大都不太合适,最终看到某it培训公司一位讲师用

uicollectionview:一行代码实现图片无限轮播器的方法,当然想一行代码实现轮播功能,前期还是有一些工作要做。下面就把这个方法分享给大家!

一、图片无限轮播实现效果图:

一行iOS代码实现图片无限轮播器

图片无限轮播.gif

二、实现原理与分析:

假设有三张图片0、1、2,想要实现无限轮播,我们可以将uicollectionview的cell个数设为图片的个数 x 3,也就是把三张图片重复添加到9个cell中,可以把无限轮播分解成五种特殊的状态(五个临界点),轮播开始时为初始状态,在定时器的作用下依次滚动到最后一个cell,此时为右临界状态显示的是第2张图片,若想继续无缝滚动到第0图片,我们可以偷偷的将collectionview滚动到第三个cell上,可以看第四幅转态图此时显示的依然是第2张图片,这样再次滚动就是第0张图,这样就实现了cell向左滚动的无限循环轮播;向右滚动的原理一样,就是第三幅图到第五幅图的变化。

一行iOS代码实现图片无限轮播器

初始界状态.png

一行iOS代码实现图片无限轮播器

右临界状态.png

一行iOS代码实现图片无限轮播器

左临界状态.png

一行iOS代码实现图片无限轮播器

paste_image.png

一行iOS代码实现图片无限轮播器

paste_image.png

三、代码:

一行iOS代码实现图片无限轮播器

类文件.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文件

?
1
2
3
4
5
#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文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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文件

?
1
2
3
4
5
6
7
8
#import <uikit/uikit.h>
 
@interface jfloopview : uiview
 
//jfloopview初始化方法
- (instancetype)initwithimagearray:(nsarray *)imagearray;
 
@end

jfloopview.m文件

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#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文件

?
1
2
3
4
#import <uikit/uikit.h>
@interface jfloopviewcell : uicollectionviewcell
@property (nonatomic, copy) nsstring *imagename;
@end

jfloopviewcell.m文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#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文件

?
1
2
3
4
5
#import <uikit/uikit.h>
 
@interface jfloopviewlayout : uicollectionviewflowlayout
 
@end

jfloopviewlayout.m文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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文件

?
1
2
3
4
5
#import <uikit/uikit.h>
 
@interface jfmainviewcontroller : uiviewcontroller
 
@end

jfmainviewcontroller.m文件

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#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的位置会变化。

一行iOS代码实现图片无限轮播器

图片无限轮播bug展示.gif

四、总结:

1、实现无限轮播器的主要控件是uicollectionview和uipagecontrol,
2、封装好工具类以后再使用时一行_loopview = [[jfloopview alloc] initwithimagearray:imagearray];代码,然后设置frame就可以复用无限轮播器。
3、合理切换图片和图片排列的方法,加上恰当地使用uicollectionview提供的代理方法就可以完美的实现无限轮播器。

写在最后:

下一篇文章讲用uicollectionview实现电商app首页的方法:

一行iOS代码实现图片无限轮播器
电商app的首页展示.gif

如果你有好的方法敬请分享,感谢你的阅读!欢迎关注和评论!

源码地址:链接: https://pan.baidu.com/s/1nv5fqzj 密码: qz3u

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://www.jianshu.com/p/dd5eef3bc6d0

延伸 · 阅读

精彩推荐
  • IOSIOS 屏幕适配方案实现缩放window的示例代码

    IOS 屏幕适配方案实现缩放window的示例代码

    这篇文章主要介绍了IOS 屏幕适配方案实现缩放window的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要...

    xiari5772021-06-01
  • IOS解析iOS开发中的FirstResponder第一响应对象

    解析iOS开发中的FirstResponder第一响应对象

    这篇文章主要介绍了解析iOS开发中的FirstResponder第一响应对象,包括View的FirstResponder的释放问题,需要的朋友可以参考下...

    一片枫叶4662020-12-25
  • IOSiOS中tableview 两级cell的展开与收回的示例代码

    iOS中tableview 两级cell的展开与收回的示例代码

    本篇文章主要介绍了iOS中tableview 两级cell的展开与收回的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    J_Kang3862021-04-22
  • IOS关于iOS自适应cell行高的那些事儿

    关于iOS自适应cell行高的那些事儿

    这篇文章主要给大家介绍了关于iOS自适应cell行高的那些事儿,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    daisy6092021-05-17
  • IOSiOS布局渲染之UIView方法的调用时机详解

    iOS布局渲染之UIView方法的调用时机详解

    在你刚开始开发 iOS 应用时,最难避免或者是调试的就是和布局相关的问题,下面这篇文章主要给大家介绍了关于iOS布局渲染之UIView方法调用时机的相关资料...

    windtersharp7642021-05-04
  • IOSiOS通过逆向理解Block的内存模型

    iOS通过逆向理解Block的内存模型

    自从对 iOS 的逆向初窥门径后,我也经常通过它来分析一些比较大的应用,参考一下这些应用中某些功能的实现。这个探索的过程乐趣多多,不仅能满足自...

    Swiftyper12832021-03-03
  • IOSIOS开发之字典转字符串的实例详解

    IOS开发之字典转字符串的实例详解

    这篇文章主要介绍了IOS开发之字典转字符串的实例详解的相关资料,希望通过本文能帮助到大家,让大家掌握这样的方法,需要的朋友可以参考下...

    苦练内功5832021-04-01
  • IOSiOS 雷达效果实例详解

    iOS 雷达效果实例详解

    这篇文章主要介绍了iOS 雷达效果实例详解的相关资料,需要的朋友可以参考下...

    SimpleWorld11022021-01-28