实现一个简单易用的无限轮播视图YWLoopScrollView

代码效果:

loop.gif

github Demo地址:wang66/YWLoopScrollViewDemo


用法:

创建YWLoopScrollView视图的实例,并设置数据源和相关属性,并添加在父视图上。而且可以设置代理实现其代理方法,将有关数据回调出来。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.titleLabel.text = @"YWLoopScrollView";
    self.titleView.backgroundColor = RGB(31, 162, 252);
    
    NSArray *imagesArr = @[IMAGE(@"img01.jpeg"),IMAGE(@"img02.jpeg"),IMAGE(@"img03.jpeg"), IMAGE(@"img04.jpeg")]; // ,IMAGE(@"img05.jpeg")
    YWLoopScrollView *loopScrollView = [[YWLoopScrollView alloc] initWithFrame:CGRectMake(0, 0, Width_MainScreen, 250) images:imagesArr];
    loopScrollView.scrollInterval = 2.f;
    loopScrollView.isAutoScroll = YES;  // default is YES
    loopScrollView.delegate = self;
    [self.contentView addSubview:loopScrollView];
}

#pragma mark - YWLoopScrollViewDelegate
- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView currentPageIndex:(NSInteger)index image:(id)image
{
    NSLog(@"❤:currentPageIndex is %d", (int)index);
}

- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView didSelectedPageIndex:(NSInteger)index image:(id)image
{
    NSLog(@"❤:didSelectedPageIndex is %d", (int)index);
    SecondViewController *secondVC = [SecondViewController new];
    secondVC.image = image;
    [self.navigationController pushViewController:secondVC animated:YES];
}

YWLoopScrollView.h接口:

#import <UIKit/UIKit.h>

@class YWLoopScrollView;
@protocol YWLoopScrollViewDelegate <NSObject>

- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView currentPageIndex:(NSInteger)index image:(id)image;
- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView didSelectedPageIndex:(NSInteger)index image:(id)image;

@end

@interface YWLoopScrollView : UIView

@property (nonatomic, strong)UIColor        *pageControlDefaultColor; // pageControl的默认颜色
@property (nonatomic, strong)UIColor        *pageControlSelectedColor; // pageControl当前点的颜色
@property (nonatomic, assign)CGFloat         scrollInterval; // 滚动时间
@property (nonatomic, assign)CGRect          pageControlRect; // pageControl的frame
@property (nonatomic, assign)BOOL            isAutoScroll; // 是否自动滚动
@property (nonatomic, weak)id<YWLoopScrollViewDelegate> delegate;

- (instancetype)initWithFrame:(CGRect)frame images:(NSArray *)images;
//- (instancetype)initWithFrame:(CGRect)frame imagesUrl:(NSArray *)imagesUrl;
@end


@interface YWCollectionCell : UICollectionViewCell

@end```

---

### 无限循环轮播的原理:

说起轮播图片,一般可以创建一个``UIScrollView``,在上面添加多个``UIImageView``实现。也可以直接使用``UICollectionView``来实现,而且后者更好一些,它有复用机制,性能可能更好点。``YWLoopScrollView``是用``collectionView``实现的。

无限循环轮播,即可以往左右无限滚动。当前屏幕为最后一张图片时,继续往后滚动则重新从第一张图片开始显示;若当前屏幕为第一张图片,往前滚动则是最后一张图片依次往前滚动。如下,假如数据源是``A``,``B``,``C``,``D``四张图片,默认是``A``在占据屏幕的,往后滑动屏幕,则依次出现图片``B``,``C``,``D``。当当前屏幕为最后一张图片``D``时,继续往右滑动,则重新从``A``开始依次显示。同理,若当前屏幕是显示``A``图片的,则往左滑动时会从``D``开始依次显示图片。

##### 怎么实现上述效果呢?看下图(来自知乎:[ios轮播图实现原理?](https://www.zhihu.com/question/28720980))。
![5b11921b4dfc8c362d1a78e3e0e17aa4_b.jpg](http://upload-images.jianshu.io/upload_images/988593-36804034d492bada.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>我们可以把滚动视图``collectionView``的数据源个数设为原始数据源N+2,这样的话滚动视图的滚动范围``contentSize``则多出来两张图片范围。在原始数据源的最后追加一项``A``图片,在原始数据源的开头追加一项``D``图片。如此一来,当我们滑动到``D``图片继续往后滑动时会滑动到追加的``A``图片上,若此时,我们将``collectionView``的``contentOffset``以非动画形式设置为原始``A``的位置,让``collectionView``回到第一张图片的位置。如此,便可循环滚动。

>往左滑动也同理。``A``原本就是第一张图片了,但是因为我们在前面追加了``D``图片,从``A``往左滑动,便滑动到了``D``,此时,若我们以非动画的形式设置``collectionView``的``contentOffset``为原始``D``的位置,让``collectionView``回到最后一张图片的位置。如此也实现了循环滚动。


##### 用代码来实现上述原理的逻辑:

pragma mark - scrollView delegate

// 减速停止时触发

  • (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
    [self scrollRefresh];
    }
    // setContentOffset/scrollRectVisible:animated: 这些滚动动画结束时触发
  • (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
    {
    [self scrollRefresh];
    }

pragma mark - 循环轮播的核心逻辑

  • (void)scrollRefresh
    {
    NSInteger dataIndex = floor(_collecionView.contentOffset.x/CGRectGetWidth(self.frame));
    NSIndexPath *indexPath = [_collecionView indexPathForItemAtPoint:_collecionView.contentOffset];
    NSInteger currentPage = [self imageIndexFromRowIndex:indexPath.row];

    if(dataIndex==0){
    [_collecionView scrollRectToVisible:CGRectMake(CGRectGetWidth(self.frame)*_imagesArr.count, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)) animated:NO];
    _pageControl.currentPage = _imagesArr.count-1;
    }
    else if(dataIndex==_imagesArr.count+1){
    [_collecionView scrollRectToVisible:CGRectMake(CGRectGetWidth(self.frame), 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)) animated:NO];
    _pageControl.currentPage = 0;
    }else{
    _pageControl.currentPage = currentPage;
    }

    NSLog(@"---❤%d---",(int)dataIndex);

    // callback
    if([self.delegate respondsToSelector:@selector(ywLoopScrollView:currentPageIndex:image:)]){
    [self.delegate ywLoopScrollView:self currentPageIndex:currentPage image:_imagesArr[currentPage]];
    }
    }

// collectionView 每行对应的图片数据

  • (NSInteger)imageIndexFromRowIndex:(NSInteger)rowIndex
    {
    if(rowIndex==0){
    return self.imagesArr.count-1;
    }else if(rowIndex==self.imagesArr.count+1){
    return 0;
    }else{
    return rowIndex-1;
    }
    }

上述原理的代码都在``scrollRefresh``这个方法里,该方法是在``scrollView``以下两个代码方法执行的。说到这里,有必要全面了解一下``UIScrollView``的各个代理方法触发时机和作用:[ScrollView的基本用法丶代理方法](http://www.cnblogs.com/longiang7510/p/5368197.html)

---

### 用``NSTimer``实现定时自动滑动图片:

  • (void)startAutoScroll
    {
    [self stopAutoScroll];
    _timer = [NSTimer scheduledTimerWithTimeInterval:_scrollInterval target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
    }

  • (void)stopAutoScroll
    {
    if(_timer){
    [_timer invalidate];
    }
    }

// 定时器触发的自动滚动

  • (void)nextPage
    {
    if(_imagesArr.count==0||_imagesArr.count==1){
    return;
    }

    CGPoint offset = _collecionView.contentOffset;
    NSIndexPath *indexPath = [_collecionView indexPathForItemAtPoint:offset];

    [_collecionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row+1 inSection:indexPath.section] atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
    }

因为``nextPage``方法里执行了``scrollToItemAtIndexPath:atScrollPosition:animation:``方法,它会触发``scrollView``的代理方法``scrollViewDidEndScrollingAnimation:``,从而执行``scrollRefresh``方法里的轮播逻辑。




最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,977评论 4 60
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,259评论 25 707
  • 在这个微信时代,每个人都微信上都有各式各样的微信群,而留意关心的没有几个,进行互动的则更少,或者,你自己也运营微信...
    龙大师阅读 1,448评论 1 0
  • 作者:余小鱼 链接:https://www.zhihu.com/question/26189061/answer/...
    礼小礼er阅读 278评论 0 0