SDCycleScrollView是使用UICollectionView实现的轮播,图片的网络获取是依赖SDWebImage,也就是说使用SDCycleScrollView你就必须的使用SDWebImage。下面来简单介绍一下SDCycleScrollView的实现原理;
1.SDCycleScrollView的大部分逻辑代码的实现都是放在“SDCycleScrollView.m”文件中,着这个文件里面提供了几个类方法用来初始化。
/** 初始轮播图(推荐使用) */
+ (instancetype)cycleScrollViewWithFrame:(CGRect)frame delegate:(id<SDCycleScrollViewDelegate>)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;
基本的使用方法
SDCycleScrollView *cycleScrollView = [SDCycleScrollView cycleScrollViewWithFrame:CGRectMake(0, 64, w, 180) shouldInfiniteLoop:YES imageNamesGroup:imageNames];
cycleScrollView.delegate = self;
cycleScrollView.pageControlStyle = SDCycleScrollViewPageContolStyleAnimated;
[demoContainerView addSubview:cycleScrollView];
cycleScrollView.scrollDirection = UICollectionViewScrollDirectionVertical;
2.在创建方法中实现initWithFrame中实现属性的初始化、设置默认值,同时创建collectionView,在这里他自定义了一个UICollectionCell(SDCollectionViewCell),在这个cell里面添加imageView、label、font等属性。
@interface SDCollectionViewCell : UICollectionViewCell
@property (weak, nonatomic) UIImageView *imageView;
@property (copy, nonatomic) NSString *title;
@property (nonatomic, strong) UIColor *titleLabelTextColor;
@property (nonatomic, strong) UIFont *titleLabelTextFont;
@property (nonatomic, strong) UIColor *titleLabelBackgroundColor;
@property (nonatomic, assign) CGFloat titleLabelHeight;
@property (nonatomic, assign) NSTextAlignment titleLabelTextAlignment;
@property (nonatomic, assign) BOOL hasConfigured;
/** 只展示文字轮播 */
@property (nonatomic, assign) BOOL onlyDisplayText;
@end
3.这里是实现的全部。在这里也是通过timer来自动轮播的,这里是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];
}
计时器执行的方法里面的主要方法就是获取当前的currentIndex,以及滚动到当前的index,我们着重看一下滚动到当前的index这个方法的实现,这里他是做了一个判断,当前的index >= count的时候,就直接滚动到_totalItemsCount *0.5的位置,在这里作者使用这样一句代码
_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的位置开始轮播
- (void)adjustWhenControllerViewWillAppera
{
long targetIndex = [self currentIndex];
if (targetIndex < _totalItemsCount) {
[_mainView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:targetIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
}
以上是我的一些心得,希望可以帮助到别人,如果有不对的地方欢迎指正。