實(shí)現(xiàn)一個簡單易用的無限輪播視圖YWLoopScrollView

代碼效果:

loop.gif

github Demo地址:wang66/YWLoopScrollViewDemo


用法:

創(chuàng)建YWLoopScrollView視圖的實(shí)例驮审,并設(shè)置數(shù)據(jù)源和相關(guān)屬性头岔,并添加在父視圖上。而且可以設(shè)置代理實(shí)現(xiàn)其代理方法峡竣,將有關(guān)數(shù)據(jù)回調(diào)出來适掰。

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.titleLabel.text = @"YWLoopScrollView";
    self.titleView.backgroundColor = RGB(31, 162, 252);
    
    NSArray *imagesArr = @[IMAGE(@"img01.jpeg"),IMAGE(@"img02.jpeg"),IMAGE(@"img03.jpeg"), IMAGE(@"img04.jpeg")]; // ,IMAGE(@"img05.jpeg")
    YWLoopScrollView *loopScrollView = [[YWLoopScrollView alloc] initWithFrame:CGRectMake(0, 0, Width_MainScreen, 250) images:imagesArr];
    loopScrollView.scrollInterval = 2.f;
    loopScrollView.isAutoScroll = YES;  // default is YES
    loopScrollView.delegate = self;
    [self.contentView addSubview:loopScrollView];
}

#pragma mark - YWLoopScrollViewDelegate
- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView currentPageIndex:(NSInteger)index image:(id)image
{
    NSLog(@"?:currentPageIndex is %d", (int)index);
}

- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView didSelectedPageIndex:(NSInteger)index image:(id)image
{
    NSLog(@"?:didSelectedPageIndex is %d", (int)index);
    SecondViewController *secondVC = [SecondViewController new];
    secondVC.image = image;
    [self.navigationController pushViewController:secondVC animated:YES];
}

YWLoopScrollView.h接口:

#import <UIKit/UIKit.h>

@class YWLoopScrollView;
@protocol YWLoopScrollViewDelegate <NSObject>

- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView currentPageIndex:(NSInteger)index image:(id)image;
- (void)ywLoopScrollView:(YWLoopScrollView *)scrollView didSelectedPageIndex:(NSInteger)index image:(id)image;

@end

@interface YWLoopScrollView : UIView

@property (nonatomic, strong)UIColor        *pageControlDefaultColor; // pageControl的默認(rèn)顏色
@property (nonatomic, strong)UIColor        *pageControlSelectedColor; // pageControl當(dāng)前點(diǎn)的顏色
@property (nonatomic, assign)CGFloat         scrollInterval; // 滾動時間
@property (nonatomic, assign)CGRect          pageControlRect; // pageControl的frame
@property (nonatomic, assign)BOOL            isAutoScroll; // 是否自動滾動
@property (nonatomic, weak)id<YWLoopScrollViewDelegate> delegate;

- (instancetype)initWithFrame:(CGRect)frame images:(NSArray *)images;
//- (instancetype)initWithFrame:(CGRect)frame imagesUrl:(NSArray *)imagesUrl;
@end


@interface YWCollectionCell : UICollectionViewCell

@end```

---

### 無限循環(huán)輪播的原理:

說起輪播圖片类浪,一般可以創(chuàng)建一個``UIScrollView``,在上面添加多個``UIImageView``實(shí)現(xiàn)诉瓦。也可以直接使用``UICollectionView``來實(shí)現(xiàn),而且后者更好一些固额,它有復(fù)用機(jī)制煞聪,性能可能更好點(diǎn)。``YWLoopScrollView``是用``collectionView``實(shí)現(xiàn)的啄糙。

無限循環(huán)輪播云稚,即可以往左右無限滾動。當(dāng)前屏幕為最后一張圖片時碱鳞,繼續(xù)往后滾動則重新從第一張圖片開始顯示窿给;若當(dāng)前屏幕為第一張圖片,往前滾動則是最后一張圖片依次往前滾動崩泡。如下淘菩,假如數(shù)據(jù)源是``A``,``B``,``C``,``D``四張圖片,默認(rèn)是``A``在占據(jù)屏幕的季春,往后滑動屏幕热康,則依次出現(xiàn)圖片``B``,``C``,``D``姐军。當(dāng)當(dāng)前屏幕為最后一張圖片``D``時尖淘,繼續(xù)往右滑動,則重新從``A``開始依次顯示村生。同理,若當(dāng)前屏幕是顯示``A``圖片的辽话,則往左滑動時會從``D``開始依次顯示圖片。

##### 怎么實(shí)現(xiàn)上述效果呢贴捡?看下圖(來自知乎:[ios輪播圖實(shí)現(xiàn)原理村砂?](https://www.zhihu.com/question/28720980))屹逛。
![5b11921b4dfc8c362d1a78e3e0e17aa4_b.jpg](http://upload-images.jianshu.io/upload_images/988593-36804034d492bada.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>我們可以把滾動視圖``collectionView``的數(shù)據(jù)源個數(shù)設(shè)為原始數(shù)據(jù)源N+2,這樣的話滾動視圖的滾動范圍``contentSize``則多出來兩張圖片范圍罕模。在原始數(shù)據(jù)源的最后追加一項(xiàng)``A``圖片,在原始數(shù)據(jù)源的開頭追加一項(xiàng)``D``圖片蒿讥。如此一來抛腕,當(dāng)我們滑動到``D``圖片繼續(xù)往后滑動時會滑動到追加的``A``圖片上,若此時摔敛,我們將``collectionView``的``contentOffset``以非動畫形式設(shè)置為原始``A``的位置全封,讓``collectionView``回到第一張圖片的位置。如此行楞,便可循環(huán)滾動土匀。

>往左滑動也同理。``A``原本就是第一張圖片了池颈,但是因?yàn)槲覀冊谇懊孀芳恿薫`D``圖片钓丰,從``A``往左滑動,便滑動到了``D``琢歇,此時,若我們以非動畫的形式設(shè)置``collectionView``的``contentOffset``為原始``D``的位置李茫,讓``collectionView``回到最后一張圖片的位置魄宏。如此也實(shí)現(xiàn)了循環(huán)滾動。


##### 用代碼來實(shí)現(xiàn)上述原理的邏輯:

pragma mark - scrollView delegate

// 減速停止時觸發(fā)

  • (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
    {
    [self scrollRefresh];
    }
    // setContentOffset/scrollRectVisible:animated: 這些滾動動畫結(jié)束時觸發(fā)
  • (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
    {
    [self scrollRefresh];
    }

pragma mark - 循環(huán)輪播的核心邏輯

  • (void)scrollRefresh
    {
    NSInteger dataIndex = floor(_collecionView.contentOffset.x/CGRectGetWidth(self.frame));
    NSIndexPath *indexPath = [_collecionView indexPathForItemAtPoint:_collecionView.contentOffset];
    NSInteger currentPage = [self imageIndexFromRowIndex:indexPath.row];

    if(dataIndex==0){
    [_collecionView scrollRectToVisible:CGRectMake(CGRectGetWidth(self.frame)*_imagesArr.count, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)) animated:NO];
    _pageControl.currentPage = _imagesArr.count-1;
    }
    else if(dataIndex==_imagesArr.count+1){
    [_collecionView scrollRectToVisible:CGRectMake(CGRectGetWidth(self.frame), 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame)) animated:NO];
    _pageControl.currentPage = 0;
    }else{
    _pageControl.currentPage = currentPage;
    }

    NSLog(@"---?%d---",(int)dataIndex);

    // callback
    if([self.delegate respondsToSelector:@selector(ywLoopScrollView:currentPageIndex:image:)]){
    [self.delegate ywLoopScrollView:self currentPageIndex:currentPage image:_imagesArr[currentPage]];
    }
    }

// collectionView 每行對應(yīng)的圖片數(shù)據(jù)

  • (NSInteger)imageIndexFromRowIndex:(NSInteger)rowIndex
    {
    if(rowIndex==0){
    return self.imagesArr.count-1;
    }else if(rowIndex==self.imagesArr.count+1){
    return 0;
    }else{
    return rowIndex-1;
    }
    }

上述原理的代碼都在``scrollRefresh``這個方法里,該方法是在``scrollView``以下兩個代碼方法執(zhí)行的予跌。說到這里,有必要全面了解一下``UIScrollView``的各個代理方法觸發(fā)時機(jī)和作用:[ScrollView的基本用法丶代理方法](http://www.cnblogs.com/longiang7510/p/5368197.html)

---

### 用``NSTimer``實(shí)現(xiàn)定時自動滑動圖片:

  • (void)startAutoScroll
    {
    [self stopAutoScroll];
    _timer = [NSTimer scheduledTimerWithTimeInterval:_scrollInterval target:self selector:@selector(nextPage) userInfo:nil repeats:YES];
    }

  • (void)stopAutoScroll
    {
    if(_timer){
    [_timer invalidate];
    }
    }

// 定時器觸發(fā)的自動滾動

  • (void)nextPage
    {
    if(_imagesArr.count==0||_imagesArr.count==1){
    return;
    }

    CGPoint offset = _collecionView.contentOffset;
    NSIndexPath *indexPath = [_collecionView indexPathForItemAtPoint:offset];

    [_collecionView scrollToItemAtIndexPath:[NSIndexPath indexPathForItem:indexPath.row+1 inSection:indexPath.section] atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
    }

因?yàn)閌`nextPage``方法里執(zhí)行了``scrollToItemAtIndexPath:atScrollPosition:animation:``方法,它會觸發(fā)``scrollView``的代理方法``scrollViewDidEndScrollingAnimation:``烁焙,從而執(zhí)行``scrollRefresh``方法里的輪播邏輯考阱。




最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市秽之,隨后出現(xiàn)的幾起案子吃既,更是在濱河造成了極大的恐慌,老刑警劉巖河质,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件震叙,死亡現(xiàn)場離奇詭異,居然都是意外死亡乐尊,警方通過查閱死者的電腦和手機(jī)划址,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痢缎,“玉大人,你說我怎么就攤上這事署穗∏锻荩” “怎么了?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長回溺。 經(jīng)常有香客問我混萝,道長,這世上最難降的妖魔是什么车要? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任崭倘,我火速辦了婚禮,結(jié)果婚禮上琅坡,老公的妹妹穿的比我還像新娘残家。我一直安慰自己,他們只是感情好茴晋,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布回窘。 她就那樣靜靜地躺著,像睡著了一般掀虎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上驰怎,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天二打,我揣著相機(jī)與錄音,去河邊找鬼症杏。 笑死瑞信,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逼友。 我是一名探鬼主播秤涩,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼黎烈!你這毒婦竟也來了匀谣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤必怜,失蹤者是張志新(化名)和其女友劉穎后频,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膏执,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡露久,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年毫痕,在試婚紗的時候發(fā)現(xiàn)自己被綠了迟几。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片栏笆。...
    茶點(diǎn)故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蛉加,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出针饥,到底是詐尸還是另有隱情丁眼,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布嵌施,位于F島的核電站莽鸭,受9級特大地震影響吃靠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜巢块,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一族奢、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧棚品,春花似錦廊敌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坦弟。三九已至官地,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間区丑,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宴杀,地道東北人。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓旷余,卻偏偏與公主長得像扁达,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子炉旷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評論 2 355

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