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

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网络请求之AFNetWorking 3.x 使用详情

    IOS网络请求之AFNetWorking 3.x 使用详情

    本篇文章主要介绍了IOS网络请求之AFNetWorking 3.x 使用详情,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    总李写代码6892021-03-04
  • IOSiOS常见的几个修饰词深入讲解

    iOS常见的几个修饰词深入讲解

    这篇文章主要给大家介绍了关于iOS常见的几个修饰词的相关资料,iOS修饰词包括assign、weak、strong、retain、copy、nonatomic、atomic、readonly、readwrite,文中通过示...

    郡王丶千夜7422021-05-10
  • IOSiOS APP实现微信H5支付示例总结

    iOS APP实现微信H5支付示例总结

    这篇文章主要介绍了iOS APP实现微信H5支付示例总结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下...

    一张小A11332021-06-01
  • IOSiOS10 Xcode8适配7个常见问题汇总

    iOS10 Xcode8适配7个常见问题汇总

    这篇文章主要为大家详细汇总了iOS10 Xcode8适配7个常见问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    索马里猫10332021-02-01
  • IOSiOS中时间与时间戳的相互转化实例代码

    iOS中时间与时间戳的相互转化实例代码

    这篇文章主要介绍了iOS中时间与时间戳的相互转化实例代码,非常具有实用价值,需要的朋友可以参考下。...

    张无忌!4812021-03-09
  • IOSiOS逆向教程之logify跟踪方法的调用

    iOS逆向教程之logify跟踪方法的调用

    这篇文章主要给大家介绍了关于iOS逆向教程之logify跟踪方法调用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学...

    Mr.Guo11472021-04-28
  • IOS谈一谈iOS单例模式

    谈一谈iOS单例模式

    这篇文章主要和大家谈一谈iOS中的单例模式,单例模式是一种常用的软件设计模式,想要深入了解iOS单例模式的朋友可以参考一下...

    彭盛凇11872021-01-19
  • IOSxcode8提交ipa失败无法构建版本问题的解决方案

    xcode8提交ipa失败无法构建版本问题的解决方案

    xcode升级到xcode8后发现构建不了新的版本。怎么解决呢?下面小编给大家带来了xcode8提交ipa失败无法构建版本问题的解决方案,非常不错,一起看看吧...

    Cinna丶7542021-02-03