神刀安全网

利用UICollectionView实现无限循环轮播图

之前写的项目,几乎每一个都会用到循环轮播图,于是很早之前就自己写了一个,并一直在使用。在使用过程中也会将出现的BUG进行修复,还会根据需求添加一些新的功能,这个功能就一直修修改改的用着。今天抽出点时间,对这份代码进行了整理和完善,现在分享出来供大家一起学习。
实现效果,如下图所示:

利用UICollectionView实现无限循环轮播图
效果图.png

思路与实现

其实在明白设计思路之后,实现起来就非常简单,所以为这里会先介绍实现的思路。

思路

我们都知道UICollectionView是系统提供的一个用于展示各种图片之类的展示的控件,用UICollectionView展示一组图片使其可以左右滑动,包括让其自动滚动,这些都非常简单。但如何让其实现无限循环滚动呢?
其实原理非常简单,就是让UICollectionView的数据源数组里面多放几组将要展示的图片,然后让UICollectionView滚动到中间位置就OK了。这里我们需要清楚:数组中多了那么多图片,会不会导致内存增加呢?其实,这个完全不用担心,因为数组中存放的是图片的内存地址,所以图片的增加不会对内存有多大的影响。明白了思路之后,就直接上代码。

实现

加载本地图片

在设置好轮播图的位置等一些基本属性之后,还需要给轮播图传一个图片数组addLocalImages:,具体实现如下:

- (void)addLocalImages:(NSArray<NSString *> *)images {     [ImagesPlayer checkElementOfImages:images];     [self.dataArray removeAllObjects];     [self.dataArray addObjectsFromArray:images];     _images = [NSArray arrayWithArray:self.dataArray];      //刷新pageControl     self.indicatorView.numberOfPages = images.count;     [self.indicatorView updateCurrentPageDisplay];      //在Updates里执行完更新操作后再执行completion回调     [self.collectionView performBatchUpdates:^{         [self.collectionView reloadData];     } completion:^(BOOL finished) {         //刷新完成让collectionView滚动到中间位置         NSInteger center = ceilf([self.collectionView numberOfItemsInSection:0] * 0.5);         NSIndexPath *indexPath = [NSIndexPath indexPathForRow:center inSection:0];         [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];         self.previousOffsetX = self.collectionView.contentOffset.x;          //开启定时器         [self removeTimer];         [self addTimer];     }]; }

这里需要注意的是:每次有新的图片数组添加进来时,都需要对UICollectionView进行reloadData才能展示新的图片,然后再让UICollectionView滚动到中间位置,但必须要等到reloadData完成才能滚动。所以这里需要用到performBatchUpdates:completion:这个方法,在updates代码块中执行对UICollectionView的更新操作,等更新操作完成再调用completion代码块中的代码。

加载网络图片

因为在项目中轮播图片是从后台获取的,所以还需要加载网络图片addNetWorkImages:placeholder:。这个方法与上面加载本地图片方法相比,就是多了一个占位图,然后利用图片地址请求网络图片,请求到图片后还需做本地缓存,具体实现如下:

- (void)setImageWithURL:(NSString *)url placeholderImage:(UIImage *)placeholder {     NSString *fileDir  = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:@"imagesCache"];     NSFileManager *fm  = [NSFileManager defaultManager];     [fm createDirectoryAtPath:fileDir withIntermediateDirectories:YES attributes:nil error:nil];     NSString *fileName = [fileDir stringByAppendingPathComponent:[self md5:url]];//MD5加密图片名全路径     UIImage *image     = [UIImage imageWithContentsOfFile:fileName];     if (image) {         self.image = image;     }else {         self.image = placeholder;         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{             NSURL *path = [NSURL URLWithString:url];             NSData *data = [NSData dataWithContentsOfURL:path];             dispatch_async(dispatch_get_main_queue(), ^{                 self.image = [UIImage imageWithData:data];             });             [data writeToFile:fileName atomically:YES];         });     } }

缓存思路:先从本地取,如果取不到就从网络请求,请求到后存在本地。
因为涉及到本地缓存,就有清理缓存的需求,calculateCacheImagesMemory计算本地缓存的图片大小,removeCacheMemory清空本地缓存,代码实现比较简单,具体可以在Demo中查看。

分页指示器

在项目中因为项目UI的要求,经常会遇到各种不同的分页指示器。功能中默认的是系统自带的UIPageControl,也提供了自定义分类指示器的接口,使用也很简单,只需要先遵守ImagesPlayerIndictorPattern协议,并实现该协议的方法就行了,具体代码如下:

- (UIView *)indicatorViewInImagesPlayer:(ImagesPlayer *)imagesPlayer {     CGFloat margin          = 5.0;     UIView *view            = [[UIView alloc] init];     CGFloat w               = 50;     CGFloat h               = 20;     CGFloat x               = CGRectGetWidth(imagesPlayer.frame) - w - margin;     CGFloat y               = CGRectGetHeight(imagesPlayer.frame) - h - margin;     view.frame              = CGRectMake(x, y, w, h);     view.backgroundColor    = [UIColor blackColor];     view.alpha              = 0.5;     view.clipsToBounds      = YES;     view.layer.cornerRadius = 5.0;     UILabel *lable          = [[UILabel alloc] initWithFrame:view.bounds];     lable.textAlignment     = NSTextAlignmentCenter;     lable.textColor         = [UIColor whiteColor];     self.lable              = lable;     [view addSubview:lable];     return view; }

返回自定义的分页指示器的样式

- (void)imagesPlayer:(ImagesPlayer *)imagesPlayer didChangedIndex:(NSInteger)index count:(NSInteger)count {     self.lable.text = [NSString stringWithFormat:@"%ld/%ld", index, count]; }

更新分页指示器的显示

事件处理

这里就对轮播图的点击事件进行处理,这里可以通过代理监听或是设置代码回调。
代码监听:遵守ImagesPlayerDelegae代理,实现imagesPlayer:didSelectImageAtIndex:方法。
代码回调:通过imageTapAction:接口设置回调代码块。
最后需要说明的是,在当前控制器的viewDidDisappear中要移除定时器removeTimer,防止没必要的CPU消耗。
至此,整个轮播图的基本功能都已实现,大家可以下载Demo,同时也欢迎大家提出你的想法或意见,我们一起相互学习,共同进步!!!

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » 利用UICollectionView实现无限循环轮播图

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址