需求如下:
简单来说就是几张图片轮播滚动。
原理:采用UICollectionView的重用机制和循环滚动的方式实现图片的轮播滚动。
可以实现的需求方式有:
1、本地加载:可以创建不带标题的图片轮播器
2、网络加载:创建带标题的图片轮播器(支持自定义分页控件图标颜色的修改)
3、网络加载:创建自定义图片的pageControlDot的图片轮播器
{currentPageDotImage,pageDotImage}
需要在项目中: pod 'SDCycleScrollView'
在使用的地方:#import "SDCycleScrollView.h"
注意事项
由于该库中图片处理采用了SDWebImage所以需要导入第三方库SDWebImage
首先我们先看下代码结构:
SDCycleScrollView实现的代码都放在SDCycleScrollView.m中。
项目中如果想使用并初始化SDCycleScrollView,可以使用如下方式:
/** 初始轮播图(推荐使用) */
+ (instancetype)cycleScrollViewWithFrame:(CGRect)frame delegate:(id)delegate placeholderImage:(UIImage *)placeholderImage;
+ (instancetype)cycleScrollViewWithFrame:(CGRect)frame imageURLStringsGroup:(NSArray *)imageURLStringsGroup;
/** 本地图片轮播初始化方式 */
+ (instancetype)cycleScrollViewWithFrame:(CGRect)frame imageNamesGroup:(NSArray *)imageNamesGroup;
/** 本地图片轮播初始化方式2,infiniteLoop:是否无限循环 */
+ (instancetype)cycleScrollViewWithFrame:(CGRect)frame shouldInfiniteLoop:(BOOL)infiniteLoop imageNamesGroup:(NSArray *)imageNamesGroup;
结合本次需求,我采用了推荐使用的方式进行初始化
UIView *infoView = [[UIView alloc] init];
infoView.backgroundColor = [UIColor whiteColor];
[scrollView addSubview:infoView];
NSArray *imagesURLStrings = [self.model.resources_list valueForKey:@"resource_url"];
SDCycleScrollView *cycleScrollView = [SDCycleScrollView cycleScrollViewWithFrame:CGRectMake(24, 14, kSCREEN_WIDTH - 48 , (kSCREEN_WIDTH - 48) / 327 * 160) delegate:self placeholderImage:[UIImage imageNamed:@"placeholder"]];
cycleScrollView.pageControlAliment = SDCycleScrollViewPageContolAlimentCenter;
cycleScrollView.currentPageDotColor = [UIColor whiteColor];
cycleScrollView.imageURLStringsGroup = imagesURLStrings;
cycleScrollView.autoScrollTimeInterval = 5;
cycleScrollView.currentPageDotColor = [UIColor ZHBlueColor];
cycleScrollView.pageDotColor = [UIColor whiteColor];
cycleScrollView.layer.masksToBounds = YES;
cycleScrollView.layer.cornerRadius = 4;
[infoView addSubview:cycleScrollView];
我看到源代码中实现自动轮播滚动代码是这样子滴
通过创建一个Timer,开启后加到runloop中,目的是防止滑动工程中出现的卡顿现象。
- (void)setupTimer
{
[self invalidateTimer]; // 创建定时器前先停止定时器,不然会出现僵尸定时器,导致轮播频率错误。
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:self.autoScrollTimeInterval target:self selector:@selector(automaticScroll) userInfo:nil repeats:YES];
_timer = timer;
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
无线循环中添加timer的目的是要获取到当前的index,以及滚动到当前的index,作者是这样实现的:
_totalItemsCount = self.infiniteLoop ? self.imagePathsGroup.count * 100 : self.imagePathsGroup.count;
然后作者创建了count * 100的这样的一个collectionView,每次都是从中间位置开始轮播。当currentIndex >= _totalItemsCount的时候就会将contentOffset设置到_totalItemsCount *0.5的位置
- (void)scrollToIndex:(int)targetIndex
{
if (targetIndex >= _totalItemsCount) {
if (self.infiniteLoop) {
targetIndex = _totalItemsCount * 0.5;
[_mainView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:targetIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
return;
}
[_mainView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:targetIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
在layoutSubViews方法中作者也实现了类似的方法,初始化的时候就从_totalItemsCount *0.5的位置开始轮播
if (_mainView.contentOffset.x == 0 && _totalItemsCount) {
int targetIndex = 0;
if (self.infiniteLoop) {
targetIndex = _totalItemsCount * 0.5;
}else{
targetIndex = 0;
}
[_mainView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:targetIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
并且作者还针对app置于后台一会后再置于前台,有可能会出现卡住的现象。作者在这里添加了一个解决方法:重新设置_totalItemsCount *0.5的位置开始轮播
#pragma mark - public actions
- (void)adjustWhenControllerViewWillAppera
{
long targetIndex = [self currentIndex];
if (targetIndex < _totalItemsCount) {
[_mainView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:targetIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
}
如果需要实现点击、滚动回调需要设置代理,完成相应的delegate即可。
@protocol SDCycleScrollViewDelegate
@optional
/** 点击图片回调 */
- (void)cycleScrollView:(SDCycleScrollView *)cycleScrollView didSelectItemAtIndex:(NSInteger)index;
/** 图片滚动回调 */
- (void)cycleScrollView:(SDCycleScrollView *)cycleScrollView didScrollToIndex:(NSInteger)index;