一行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

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

时间: 2017-05-22

iOS实现轮播图banner示例

楼主项目中需要有一个轮播图,因为比较简单,就自己写了个,因为是从网上弄得图片 所以用了SDWebImage 这个三方库 当然自己也可以去掉 类型后面有*号 如用使用 请自行加上..... 代码:.h 文件 @protocol TJXViewDelegate<NSObject> //判断点击的那个 -(void)sendImageName:(TJXView *)TJXView andName:(NSInteger)selectImage; @end @interface TJXView : UI

iOS实现图片轮播效果

本文实例为大家分享了IOS图片轮播效果的实现过程,供大家参考,具体内容如下 平时APP中的广告位或者滚动的新闻图片等用到的就是图片轮播这种效果,实现方式主要有两种,一种ScrollView+ImageView,另一种则是通过CollectionView,今天总结的是ScrollView这种方式. 1.图片轮播效果实现 主要实现思路是:根据图片总数及宽高设置好ScrollView的大小,每切换一张图片相当于在ScrollView上进行一个图片宽度的移动行为,并加入定时器,实现自动轮播. 如图所示,

iOS开发中使用UIScrollView实现图片轮播和点击加载

UIScrollView控件实现图片轮播 一.实现效果 实现图片的自动轮播 二.实现代码 storyboard中布局 代码: 复制代码 代码如下: #import "YYViewController.h" @interface YYViewController () <UIScrollViewDelegate> @property (weak, nonatomic) IBOutlet UIScrollView *scrollview; /**  *  页码  */ @pro

iOS仿热门话题热点轮播界面tableView

废话不多说直接上代码: 这个功能应该是挺常见的, 一个tableView到另一个tableView, 类似segment的一个东西, 我把它封装起来了: // // ViewController.m // // // Created by 高雅馨 on 16/6/3. // Copyright © 2016年 高雅馨. All rights reserved. // #import "DCNavTabBarController.h" #import "HTMacro.h&qu

IOS使用UICollectionView实现无限轮播效果

一.案例演示 本案例Demo演示的是一个首页轮播的案例,支持手动轮播和自动轮播.知识点主要集中在UICollectionView和NSTimer的使用. 二.知识储备 2.1.UICollectionView横向布局 只需要设置UICollectionViewFlowLayout的scrollDirection为UICollectionViewScrollDirectionHorizontal即可. 2.2.NSTimer的基本使用 NSTimer的初始化: 复制代码 代码如下: + (NSTi

IOS实现图片轮播无限循环效果

本文接着上篇文章进行叙述讲解,主要为大家分享了图片轮播无限循环效果的实现方法,具体内容如下 之前说到第一个问题,ScrollView移动到最后一张图片时无法移动了,这是因为ScrollView已经移动到最后,而图片又是依次排列,自然也就无法移动. 解决办法是,我们换一个思路实现图片轮播效果,ScrollView上只放三个ImageView,屏幕始终显示中间的ImageView,左边和右边的ImageView分别代表前一张图片和后一张图片,屏幕移动的时候,中间的ImageView变化,同时左右两边

iOS实现无限循环图片轮播器的封装

项目中很多时候会碰到这个需求,实现多张图片的无限循环轮转,以前做过,项目中几个地方的都用到了,当时没有封装,几个地方都拷贝几乎一样的代码,代码复用性不好,今天没事封装了一下,使用起来比较简单. 首先,说说我实现循环轮转图片的思想,在UIScrollView中添加了3个UIImageView,并排排列,我们看到的永远只是第二个UIImageView,这样的话,你一直可以向左,向右滑动,当你向左滑动是,这是你滑动到了最后一个UIImageView不能在向左边滑动了,这时,我在后面悄悄的将第二个UII

IOS图片无限轮播器的实现原理

首先实现思路:整个collectionView中只有2个cell.中间始终显示第二个cell. 滚动:向前滚动当前cell的脚标为0,向后滚动当前的cell脚标为2.利用当前cell的脚标减去1,得到+1,或者-1,来让图片的索引加1或者减1,实现图片的切换. 声明一个全局变量index来保存图片的索引,用来切换显示在当前cell的图片. 在滚动前先让显示的cell的脚标变为1.代码viewDidLoad中设置 完成一次滚动结束后,代码再设置当前的cell为第二个cell(本质上就是让当前显示的

Android图片无限轮播的实现代码

本文实例为大家分享了AnAndroid图片无限轮播的具体代码,供大家参考,具体内容如下 public class MainActivity extends Activity { private ViewPager viewPager; private LinearLayout ll_dot; private String[] imageUrls = new String[] { "http://pic8.nipic.com/20100701/5290458_114840036316_2.jpg&

swiper 自动图片无限轮播实现代码

完整代码 <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <link rel="stylesheet" href="swiper/css/swiper-3.4.2.min.css" rel="external nof

Objective-C实现无限循环轮播器

先看看效果图: 具体实现代码: 1. 控制器  // // AppDelegate.m // 无限轮播器 // // Created by zhangmi on 16/5/16. // Copyright © 2016年 Paramount Pictures. All rights reserved. // #import "ViewController.h" #import "SNInfiniteScrollView.h" @interface ViewContr

Android高级图片滚动控件实现3D版图片轮播器

大家好,好久不见了,最近由于工作特别繁忙,已经有一个多月的时间没写博客了,我也是深感惭愧.那么今天的这篇既然是阔别了一个多月的文章,当然要带来更加给力点的内容了,那么话不多说,赶快进入到今天的正题吧. 说到图片轮播器,很多的Android应用中都会带有这个功能,比如说网易新闻.淘宝等.最新我们公司的一款应用也加入了这个功能,并且在图片轮播的基础上还增加了三维立体的效果,但比较遗憾的是,整体效果并不理想,用户体验性比较糟糕.因此,我就花了点时间去编写了一个效果更好的3D图片轮播器,自我感觉还是比较

IOS开发之UIScrollView实现图片轮播器的无限滚动

IOS开发之UIScrollView实现图片轮播器的无限滚动 简介 在现在的一些App中常常见到图片轮播器,一般用于展示广告.新闻等数据,在iOS内并没有现成的控件直接实现这种功能,但是通过UIScrollView的允许分页设置,可以实现滚动轮播的功能. 轮播原理 UIScrollView对象有pagingEnable成员,如果设置为YES,那么每一个scrollView尺寸这么大的区域就会被当作一页,在滚动时会根据滚动的比例自动计算应该切换到哪一页. 无限滚动原理 要实现无限滚动,需要额外的两

iOS实现图片轮播器

有时候肯能会用到图片轮播器,做广告的效果.下面详细介绍iOS如何实现图片轮播器 1.新建一个项目,导入5张图片(为了代码方便,我把图片命名规范了,其实无所谓) 2.在mainstoryboard中拖入ScrollView和Page Control(也可以代码写,或者是自定义xib) 设置page control的 Current Page属性,决定轮播的当前页显示的颜色 3.接下来就是正式代码了 //(1)将需要展⽰的内容添加到UIScrollView中 //(2)设置UIScrollView的

iOS Swift利用UICollectionView实现无限轮播功能(原理)详解

前言 作为一个资深(自认为)iOS程序猿,会经常用到轮播图,上一次使用UIScrollView实现无限轮播的效果,这一次在Swift语言中,我使用UICollectionView再为大家讲解一次无限轮播的实现原理. 先上图: UICollectionView-无限轮播.gif 首先需要实现了就是UICollectionView的分页,这个很简单: collectionView.isPagingEnabled = true 接下来就是原理,在UICollectionView的两端需要先添加两张图片

jquery实现图片轮播器

一.轮播器 1.HTML框架 <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>图片轮播器</title> <link rel="stylesheet" type="text/css" href="slider.css" rel="