浅析SDCycleScrollView实现原理

易成天
2023-12-01

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];
    }
}

以上是我的一些心得,希望可以帮助到别人,如果有不对的地方欢迎指正。

 类似资料: