iOS

浅析实现无限轮播的两种方式

Posted by 易博 on June 9, 2017

轮播图使用的场景非常多,一般情况下不会使用到无限轮播。大多数的场景是轮播到最后一张图时强制切换contentOffset,这样最后一张和第一张图过渡就显得不平滑,接下来主要浅析两种实现平滑无限轮播的优化方案。为什么说是优化方案,一般在做广告轮播的时候,不会有太多数目的图片展示需求,也就5张左右,这个时候性能优化没有什么特别需要考虑。一旦数目变大,比如20,那这个时候就需要考虑性能优化

第一种:采用3个UIImageView来实现

这种方式较平时用的有多少图片就初始化多少的imageview实现方式类似,但是我们不会在一开始初始化所有的图片,因为就算全部初始化,那些不显示的图片用户是看不到的,没有必要放那占用着,完全可以在需要展示的时候再初始化。下面是实现思路

整个思路就是初始化scrollview的宽度是5个imageview宽,初始化3个imageview,imageview1显示最后一张图片,imageview2显示第一张图片,imageview2显示第二张图片。然后在每次滑动的时候,动态的去改变这个三个imageview的内容和scrollview的contentOffset,从而达到无限轮播的效果。如下图所示

第二种:采用UICollectionView来实现

UICollectionView想必都不陌生,为什么要用UICollectionView来实现无限轮播图呢?原因是跟UITableView一样,基于系统优化好的复用机制,能让无限轮播得到相当好的资源优化。但是这个无限循环是一个假的无限循环的效果,为什么呢?看下面的实现思路

整个思路就是初始化一个cell数目比较大(比如5000)的UICollectionView,cell就是我们要展示的图片。然后初始化数据源的时候,从最中间一个开始,分别往两边循环设置数据。完成后让UICollectionView显示最中间的cell,这样滑动的时候就有了无限循环的效果。这也就是为什么一开始说是假循环的原因,如果真的遇到了一直滑下去的操作,到最后肯定是滑不动了。如下图所示

#####关键代码实现

UICollectionView的初始化

//自定义UICollectionView风格
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];  
flowLayout.itemSize = frame.size;  
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;  
flowLayout.minimumLineSpacing = 0;  

self.collectionView = [[UICollectionView alloc] initWithFrame:self.bounds collectionViewLayout:flowLayout];
//设置代理和数据源
self.collectionView.delegate = self;  
self.collectionView.dataSource = self;  
self.collectionView.showsHorizontalScrollIndicator = NO;  
//允许分页
self.collectionView.pagingEnabled = YES;  
self.collectionView.backgroundColor = [UIColor lightGrayColor];  
[self addSubview:self.collectionView];  
//注册cell
[self.collectionView registerClass:[CarouselCell class] forCellWithReuseIdentifier:@"carouselCell"];

数据源设置完毕后让UICollectionView跳转到指定的cell

//设置cell的最大数和默认显示的cell索引
#define TotalRowsInSection (2000 * self.dataSources.count)  
#define DefaultRow (NSUInteger)(TotalRowsInSection * 0.5) 

[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:DefaultRow inSection:0] atScrollPosition:UICollectionViewScrollPositionLeft animated:NO]; 

cell的初始化代理事件

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath  
{  
    static NSString *ID = @"carouselCell";  

    CarouselCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:ID forIndexPath:indexPath];  
    if (!cell) {  
        cell = [[NSBundle mainBundle] loadNibNamed:@"CarouselCell" owner:self options:nil][0];  
    }  
    cell.dataModel = self.dataSources[indexPath.item % self.dataSources.count];  
    return cell;  
}

滑动一页之后修改pageControll的当前页码

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath  
{  
    NSIndexPath *visiablePath = [[collectionView indexPathsForVisibleItems] firstObject];  
    //设置pageControl的当前页  
    self.pageControl.currentPage = visiablePath.item % self.dataSources.count;  
}

cell的点击事件

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath  
{  
    NSInteger index = indexPath.item % self.dataSources.count;  
    if ([self.delegate respondsToSelector:@selector(clickedAtIndex:)]) {  
        [self.delegate clickedAtIndex:index];  
    }  
}