UIcollectionview实现无限轮播

作者: HH思無邪 | 来源:发表于2019-04-08 23:39 被阅读3次

参考 SDCycleScrollView轮播框架的巧妙设计,自己动手实现啦类似的需求。

无限轮播.gif
  • 需求如图,实现无限轮播效果,跟纯图片不同的是,就是内容多了点而已,没办法没有现成的框架,只有按着轮播思路写一个。

  • 实现这种需求,需要克服以下几点:

  1. 自动滚动轮播
  2. 滚动到最后一个返回第一个,且过渡要自然
  3. 计算当前显示页码

界面构成UICollectionView + UIPageControl

选用CollectionView因为用复用机制巧妙的实现无限轮播且不必担心内存开销过大,继承自ScrollView,拥有ScrollView的全部特性。

解决自动滚动 - 倒计时的应用

  • 数据为1个时,特殊处理不滚动
if (_arrayData.count > 1) {
      self.collectionView.scrollEnabled = YES;
      //处理是否自动滑动,定时器问题
      [self setAutoScroll:self.autoScroll];
  }else{
      self.collectionView.scrollEnabled = NO;
      [self setAutoScroll:NO];
  }
  • 控制是否自动滚动
- (void)setAutoScroll:(BOOL)autoScroll {
    
    _autoScroll = autoScroll;
    
    //创建之前,停止定时器
    [self invalidateTimer];
    
    if (_autoScroll) {
        [self setupTimer];
    }   
}
  • //停止定时器
- (void)invalidateTimer
{
    [_timer invalidate];
    _timer = nil;
}
  • //开启定时器
- (void)setupTimer
{
    [self invalidateTimer]; // 创建定时器前先停止定时器,不然会出现僵尸定时器,导致轮播频率错误
    
    NSTimer *timer  = [NSTimer scheduledTimerWithTimeInterval:self.autoScrollTimeInterval target:self selector:@selector(automaticScroll) userInfo:nil repeats:YES];
    
    [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    _timer = timer;
}

*//定时器调用

- (void)automaticScroll {
    if (0 == _totalItems) {
        return;
    }
    NSInteger currentIndex = [self currentIndex];    
    NSInteger targetIndex = currentIndex + 1;
    [self scrollToIndex:targetIndex];
}
  • // 滚动位置计算
- (void)scrollToIndex:(NSInteger)targetIndex{
    if (targetIndex >= _totalItems) {//调到中间的任意一组里面的 第0个图片
        if (self.infiniteLoop) {//无限循环
            targetIndex = _totalItems * 0.5;
            [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:targetIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
        }
        return;
    }
    //滚动到指定位置,打开系统默认滚动动画,看到过渡效果
    [_collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:targetIndex inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
}
  • //计算当前index
- (NSInteger)currentIndex {
    
    if (_collectionView.frame.size.width == 0 || _collectionView.frame.size
        .height == 0) {
        return 0;
    }
    NSInteger index = 0;
    if (_flowLayout.scrollDirection == UICollectionViewScrollDirectionHorizontal) {//水平滑动
        index = (_collectionView.contentOffset.x + _flowLayout.itemSize.width * 0.5) / _flowLayout.itemSize.width;
    }else{
        index = (_collectionView.contentOffset.y + _flowLayout.itemSize.height * 0.5)/ _flowLayout.itemSize.height;
    }
    //返回两个数中的最大值
    return MAX(0,index);
}

无限轮播实现 —— item数据乘以100

- (void)setArrayData:(NSArray *)arrayData
{
    _arrayData = arrayData;
   //pageControl的显示个数
    _pageControl.numberOfPages = _arrayData.count;
    // 这一句是关键,如果是无限循环,就让 item 的总数乘以 100 。
    _totalItems = self.infiniteLoop ? arrayData.count * 100 : arrayData.count;
    if (_arrayData.count > 1) {
        self.collectionView.scrollEnabled = YES;
        //处理是否自动滑动,定时器问题
        [self setAutoScroll:self.autoScroll];
    }else{
        self.collectionView.scrollEnabled = NO;
        [self setAutoScroll:NO];
    }
    [self.collectionView reloadData];
}
  • item 的总数乘以 100,为啦让手动轮播时,可以无限翻下去,虽然可以翻到最后一张就翻不动啦,应该不会有人这么无聊吧!

使用pagecontrol 如何准确显示页码

  • UIScrollViewDelegate

滚动时根据偏移量,得到当前item位置和pageControl显示页码

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    if (!self.arrayData.count) return; // 解决清除timer时偶尔会出现的问题
    int itemIndex = (int)[self currentIndex];
    int indexOnPageControl = [self pageControlIndexWithCurrentCellIndex:itemIndex];
    
    UIPageControl *pageControl = (UIPageControl *)_pageControl;
    pageControl.currentPage = indexOnPageControl;
}

优化:开始拖动时停止定时器

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    if (self.autoScroll) {
        [self invalidateTimer];
    }
}

拖动结束时开启定时器

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    if (self.autoScroll) {
        [self setupTimer];
    }
}
  • 取余计算得到当前页码
- (int)pageControlIndexWithCurrentCellIndex:(NSInteger)index {
    return (int)index % self.arrayData.count;
}

移除定时器

  • 子视图将要移除时调用
- (void)willMoveToSuperview:(UIView *)newSuperview {
    [super willMoveToSuperview:newSuperview];
    if (! newSuperview && self.timer) {
        // 销毁定时器
        [self.timer invalidate];
        self.timer = nil;
    }
}

相关文章

网友评论

    本文标题:UIcollectionview实现无限轮播

    本文链接:https://www.haomeiwen.com/subject/gizeiqtx.html