ios - 使用uicollectionView实现无限轮播

网上找到了使用scrollView实现的无限轮播的方法,需要自己写一个缓存池,不过没有找到collectionView的方法,在这边使用CollectionView实现,下面的demo本人跑起来完全没问题,如有问题的地方,希望大家指出来(里面有一些方法是自己封装的基类,会注入说明)。

基本思路:在原有的数组最前面再插入一个最后的数据,在最后面插入一个最前面的数据,这有点类似于将 12345 变成 5123451

代码:

首先是实现collectionView的数据源方法:

//每个section有多少个item
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.circularRollViewArray.count;
}

//返回每个cell,这里的CirularRollViewCell是一个自定义cell,里面就是一个简单的imageview,有想法的同学可以做的复杂一点。
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CirularRollViewCell *cell = nil;

    //从缓存池中取cell。
    cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([CirularRollViewCell class]) forIndexPath:indexPath];

    //这里的viewUpdateWithModel方法是我自己写的协议方法,就是通过数据更新视图的方法,这边你们知道就行了。
    if ([cell respondsToSelector:@selector(viewUpdateWithModel:)]) {
        [cell viewUpdateWithModel:self.circularRollViewArray[indexPath.item]];
    }

    //这一步是实现代理的方法,不写对整个轮播的实现没影响。
    if ([cell respondsToSelector:@selector(setDelegate:)]) {
        [cell performSelector:@selector(setDelegate:) withObject:self];
    }

    return cell;
}

然后在viewUpdateWithModel方法中实现重组数组,在重组之后重加在,然后将视图跳到重组过后的数组的第二个数据,即原本的第一个数据,然后启动定时器


    [self.circularRollViewArray addObject:[self.imageArray lastObject]];
    [self.circularRollViewArray addObjectsFromArray:self.imageArray];
    [self.circularRollViewArray addObject:[self.imageArray firstObject]];

    [self.circularRollView reloadData];

    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:1 inSection:0];
    [self.circularRollView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];

    //开始定时器其实就是把上一次的定时器销毁,然后再重新创建一个新的定时器
    [self startTimer];

下面的很关键,就是如何跳转的逻辑

//由于collectionView没有类似于viewDidload这样的方法,只能寄托于下面的这个代理方法。这个代理方法是在cell将要出现的时候就调用一次。
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{
    //记录将要出现的cell,来作为下面的是否换cell做判断。
    self.nextItem = indexPath.item;
}

//这个方法是上一个视图完全消失,就调用一次
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath
{

    //按照5123451来做判断,如果当前的内容是第一个5,则直接无动画的转到倒数第二个的5。如果当前内容是最后一个1,则无动画的跳转到正数第二个1。
    if (indexPath.item == 1 && self.nextItem == 0) {
        NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForItem:(self.circularRollViewArray.count - 2) inSection:0];
        [self.circularRollView scrollToItemAtIndexPath:tmpIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    }else if ((indexPath.item == (self.circularRollViewArray.count - 2)) && (self.nextItem == (self.circularRollViewArray.count - 1))){
        NSIndexPath *tmpIndexPath = [NSIndexPath indexPathForItem:1 inSection:0];
        [self.circularRollView scrollToItemAtIndexPath:tmpIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:NO];
    }else{

    }


    if(indexPath.item == self.circularRollViewArray.count - 1){
        self.endDisplayItem = 0;
    }else{

    }

}

// 通过这个方法,来控制currentPage
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    NSInteger pageNum = ((scrollView.contentOffset.x + (kscreenWidth / 2.0)) / kscreenWidth);

    if (pageNum == 0) {
        self.pageControl.currentPage = self.circularRollViewArray.count - 2;
    }else if (pageNum > 0 && pageNum < (self.circularRollViewArray.count - 1)){
        self.pageControl.currentPage = pageNum - 1;
    }else{
        self.pageControl.currentPage = 0;
    }
}

//这里是定时器所调用的方法,每调用一次,都向前一张跳转。这里为什么使用self.endDisplayItem而不是使用self.nextItem呢?原因是当你手动拖动的时候,只要稍微拖动一下,就会改变self.nextItem的值,等到定时器下次跳转的时候就会跳转两张,用户体验不是很好。
- (void)circularRollViewToNextItem
{
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:(self.endDisplayItem + 2) inSection:0];
    [self.circularRollView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    [self endTimer];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    [self startTimer];
}

大致的核心思想差不多就是那些,下面是一些控件创建的方法

//下面是collectionView的初始化和timer的初始化
//这里的_GETTER_BEGIN是自己写的一个宏定义,你们理解就好了。还有一点,当这个view被销毁的时候,一定要记得销毁定时器。
_GETTER_BEGIN(UICollectionView, circularRollView)
{
    UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
    flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    flowLayout.minimumLineSpacing = 0;
    flowLayout.itemSize = CGSizeMake(kscreenWidth, (self.CircularRollViewHeight ? self.CircularRollViewHeight : kdefineViewHeight));

    _circularRollView = [[UICollectionView alloc] initWithFrame:CGRectMake(0,0,kscreenWidth , kdefineViewHeight) collectionViewLayout:flowLayout];
    _circularRollView.showsHorizontalScrollIndicator = NO;
    _circularRollView.bounces = NO;
    _circularRollView.delegate = self;
    _circularRollView.dataSource = self;
    _circularRollView.pagingEnabled = YES;
    _circularRollView.backgroundColor = kclearColor;
    [_circularRollView registerClass:[CirularRollViewCell class] forCellWithReuseIdentifier:NSStringFromClass([CirularRollViewCell class])];
}
_GETTER_END(circularRollView)


_GETTER_BEGIN(NSTimer, timer)
{
    _timer = [NSTimer scheduledTimerWithTimeInterval:3.f target:self selector:@selector(circularRollViewToNextItem) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
_GETTER_END(timer)

- (void)endTimer
{
    [self.timer invalidate];
    self.timer = nil;
}

- (void)startTimer
{
    [self endTimer];
    [self timer];
}

只视图的搭建这就靠大家自己搭建了,我写的demo里面,pageControl用的就是原生的UIPageControl,不过在外面留一个可以自定义位置的属性。如果大家有什么疑问的地方,可以加我的QQ问我。以后有什么好的方法也会分享给大家。

本论文只是用来学习用的,无限轮播还是有第三方框架的:iCarousel https://github.com/nicklockwood/iCarousel。使用起来也非常的简单

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值