UICollectionView實(shí)現(xiàn)無(wú)限滾動(dòng)視圖

先看效果

demo.gif

實(shí)現(xiàn)思路

  1. 將原數(shù)據(jù)的總量x比較大的一個(gè)數(shù)字作為collectionVew的數(shù)據(jù)原總量
  2. 初始化時(shí)滾動(dòng)到一倍數(shù)為一半的位置
  3. 拖拽完成時(shí)定位回中間的位置
// 輪播倍數(shù)
static const int kLoopMaxMultiple = 1000;
// 一半輪播倍數(shù)
static const int kHalfLoopMaxMultiple = kLoopMaxMultiple / 2;

- (void)startScroll {
    // 滾動(dòng)到中間位置
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:kHalfLoopMaxMultiple * self.datas.count inSection:0];
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:0 animated:NO];
    [self resumeTimer];
}

/**
 獲取scrollView的index
 
 @param scrollView scrollView
 @return index
 */
- (NSInteger)indexWithScrollView:(UIScrollView * _Nonnull)scrollView {
    NSInteger index = roundf(scrollView.contentOffset.x) / scrollView.frame.size.width;
    index = (index) % self.datas.count;
    return index;
}

/**
 滾動(dòng)到指定索引

 @param scrollView scrollView
 */
- (void)scrollToIndex:(UIScrollView *)scrollView {
    NSInteger index = [self indexWithScrollView:scrollView];
    NSInteger item = kHalfLoopMaxMultiple* self.datas.count + index;
    if (index == self.datas.count - 1) {
        item = (kHalfLoopMaxMultiple - 1) * self.datas.count + index;
    }
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem: item inSection:0];
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
}

自動(dòng)滾動(dòng)

通過NSTimer實(shí)現(xiàn)定時(shí)滾動(dòng)尸疆,當(dāng)開始拖動(dòng)時(shí)取消計(jì)時(shí)器枚荣,完成拖動(dòng)后恢復(fù)

/**
 恢復(fù)定時(shí)器
 */
- (void)resumeTimer {
    // 將定時(shí)器添加到主線程
    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}


/**
 暫停定時(shí)器
 */
- (void)pauseTimer {
    [self.timer invalidate];
    _timer = nil;
}

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

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self scrollToIndex:scrollView];
    [self resumeTimer];
}

完整代碼

ViewController.m

//
//  ViewController.m
//  iOSDemo
//
//  Created by yizhaorong on 2018/1/7.
//  Copyright ? 2018年 yizhaorong. All rights reserved.
//

#import "ViewController.h"
#import "YYCollectionViewCell.h"

// 輪播倍數(shù)
static const int kLoopMaxMultiple = 1000;
// 一半輪播倍數(shù)
static const int kHalfLoopMaxMultiple = kLoopMaxMultiple / 2;

@interface ViewController () <UICollectionViewDelegate, UICollectionViewDataSource>
// 滾動(dòng)主視圖
@property (nonatomic, strong) UICollectionView *collectionView;
// 數(shù)據(jù)
@property (nonatomic, strong) NSMutableArray *datas;
// 背景色
@property (nonatomic, strong) NSMutableArray *colors;
// 分頁(yè)指示器
@property (nonatomic, strong) UIPageControl *pageControl;
// 定時(shí)器
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation ViewController

#pragma mark - LifeCircle
- (void)viewDidLoad {
    [super viewDidLoad];
    // 初始化數(shù)據(jù)
    [self setupDatas];
    // 初始化子視圖
    [self setupSubviews];
    // 開始滾動(dòng)
    [self startScroll];
}

- (void)setupSubviews {
    CGFloat top = 64;
    CGFloat height = self.view.bounds.size.height - 2 * top;
    CGSize itemSize = CGSizeMake(self.view.bounds.size.width, height);
    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
    layout.itemSize = itemSize;
    layout.minimumLineSpacing = 0;
    layout.minimumInteritemSpacing = 0;
    _collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, top, itemSize.width, height) collectionViewLayout:layout];
    [_collectionView registerClass:[YYCollectionViewCell class] forCellWithReuseIdentifier:@"YYCollectionViewCell"];
    _collectionView.pagingEnabled = YES;
    _collectionView.delegate = self;
    _collectionView.dataSource = self;
    [self.view addSubview:_collectionView];
    
    _pageControl = [UIPageControl new];
    _pageControl.numberOfPages = self.datas.count;
    _pageControl.currentPageIndicatorTintColor = [UIColor redColor];
    _pageControl.pageIndicatorTintColor = [UIColor lightGrayColor];
    CGSize pageControlSize = [_pageControl sizeForNumberOfPages:self.datas.count];
    CGFloat pageControlX = (self.view.bounds.size.width - pageControlSize.width) / 2;
    CGFloat pageControlY = CGRectGetMaxY(_collectionView.frame) - pageControlSize.height - 8;
    _pageControl.frame = CGRectMake(pageControlX, pageControlY, pageControlSize.width, pageControlSize.height);
    [self.view addSubview:_pageControl];
}

- (void)setupDatas {
    _datas = [NSMutableArray array];
    _colors = [NSMutableArray array];
    for (int i = 0; i < 3; ++i) {
        NSString *title = [NSString stringWithFormat:@"第%i個(gè)視圖", i + 1];
        UIColor *color = [UIColor colorWithRed:(arc4random_uniform(255) / 255.0) green:(arc4random_uniform(255) / 255.0) blue:(arc4random_uniform(255) / 255.0) alpha:1];
        [_datas addObject:title];
        [_colors addObject:color];
        
    }
}

- (void)startScroll {
    // 滾動(dòng)到中間位置
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:kHalfLoopMaxMultiple * self.datas.count inSection:0];
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:0 animated:NO];
    [self resumeTimer];
}

#pragma mark - Private
/**
 獲取scrollView的index
 
 @param scrollView scrollView
 @return index
 */
- (NSInteger)indexWithScrollView:(UIScrollView * _Nonnull)scrollView {
    NSInteger index = roundf(scrollView.contentOffset.x) / scrollView.frame.size.width;
    index = (index) % self.datas.count;
    return index;
}

/**
 滾動(dòng)到指定索引

 @param scrollView scrollView
 */
- (void)scrollToIndex:(UIScrollView *)scrollView {
    NSInteger index = [self indexWithScrollView:scrollView];
    NSInteger item = kHalfLoopMaxMultiple* self.datas.count + index;
    if (index == self.datas.count - 1) {
        item = (kHalfLoopMaxMultiple - 1) * self.datas.count + index;
    }
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem: item inSection:0];
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
}

/**
 恢復(fù)定時(shí)器
 */
- (void)resumeTimer {
    // 將定時(shí)器添加到主線程
    [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}


/**
 暫停定時(shí)器
 */
- (void)pauseTimer {
    [self.timer invalidate];
    _timer = nil;
}


/**
 自動(dòng)滾動(dòng)

 @param timer 定時(shí)器
 */
- (void)update:(NSTimer *)timer{
    NSInteger index = [self indexWithScrollView:self.collectionView] + 1;
    NSInteger item = kHalfLoopMaxMultiple * self.datas.count + index % self.datas.count;
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem: item inSection:0];
    [self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}


#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return self.datas.count * kLoopMaxMultiple;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    YYCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"YYCollectionViewCell" forIndexPath:indexPath];
    NSInteger index = indexPath.item % self.datas.count;
    cell.contentView.backgroundColor = self.colors[index];
    cell.titleLabel.text = self.datas[index];
    return cell;
}

#pragma mark - UIScrollViewDelegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    NSInteger index = [self indexWithScrollView:scrollView];
    self.pageControl.currentPage = index;
}

- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
    [self scrollToIndex:scrollView];
}

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

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self scrollToIndex:scrollView];
    [self resumeTimer];
}

#pragma mark - Setter And Getter
- (NSTimer *)timer {
    if (!_timer) {
        // 設(shè)置時(shí)鐘動(dòng)畫 定時(shí)器
        _timer = [NSTimer scheduledTimerWithTimeInterval:2.0f target:self selector:@selector(update:) userInfo:nil repeats:YES];
    }
    return _timer;
}

@end

YYCollectionViewCell.m

//
//  YYCollectionViewCell.m
//  iOSDemo
//
//  Created by yizhaorong on 2018/1/7.
//  Copyright ? 2018年 yizhaorong. All rights reserved.
//

#import "YYCollectionViewCell.h"

@implementation YYCollectionViewCell

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self setupSubviews];
    }
    return self;
}

- (void)setupSubviews {
    _titleLabel = [UILabel new];
    _titleLabel.textAlignment = NSTextAlignmentCenter;
    _titleLabel.textColor = [UIColor whiteColor];
    _titleLabel.font = [UIFont boldSystemFontOfSize:32];
    [self.contentView addSubview:_titleLabel];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    self.titleLabel.frame = self.bounds;
}

@end

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末抄课,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鲫寄,老刑警劉巖瓜喇,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異涕蚤,居然都是意外死亡宪卿,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門万栅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)佑钾,“玉大人,你說(shuō)我怎么就攤上這事烦粒⌒萑埽” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)兽掰。 經(jīng)常有香客問我芭碍,道長(zhǎng),這世上最難降的妖魔是什么禾进? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任豁跑,我火速辦了婚禮,結(jié)果婚禮上泻云,老公的妹妹穿的比我還像新娘艇拍。我一直安慰自己,他們只是感情好宠纯,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布卸夕。 她就那樣靜靜地躺著,像睡著了一般婆瓜。 火紅的嫁衣襯著肌膚如雪快集。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天廉白,我揣著相機(jī)與錄音个初,去河邊找鬼。 笑死猴蹂,一個(gè)胖子當(dāng)著我的面吹牛院溺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播磅轻,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼珍逸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了聋溜?” 一聲冷哼從身側(cè)響起谆膳,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎撮躁,沒想到半個(gè)月后漱病,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡把曼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年缨称,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祝迂。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡睦尽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出型雳,到底是詐尸還是另有隱情当凡,我是刑警寧澤山害,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站沿量,受9級(jí)特大地震影響浪慌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜朴则,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一权纤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乌妒,春花似錦汹想、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至侦啸,卻和暖如春槽唾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背光涂。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工庞萍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人忘闻。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓钝计,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親服赎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子葵蒂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容