代碼效果:
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``方法里的輪播邏輯考阱。