昨天將以前寫的一個循環(huán)滾動視圖重新整理了一下。以后還會繼續(xù)完善這個demo,github托管地址:
https://github.com/JerryLMJ/LMJEndlessLoopScrollView
如果此demo幫助到你,請賜給一顆star,你的鼓勵是我coding的動力
主要講一下核心的代碼什么的,具體的下載下來自己來看吧。
原理
主要是利用UIScrollView實(shí)現(xiàn),設(shè)置scrollVIew的contentSize為三倍控件寬度,不斷重置添加在scrollView上的三個內(nèi)容子視圖,從而實(shí)現(xiàn)無限循環(huán)。
用到的類別
先說一下用到的兩個自定義類別:
- NSTimer (ForLMJEndlessLoopScrollView)
// 暫停
- (void)pause;
// 重新開始
- (void)restart;
// 延遲一定時間啟動
- (void)restartAfterTimeInterval:(NSTimeInterval)interval;
- (void)pause{
if ([self isValid]) {
[self setFireDate:[NSDate distantFuture]];
}
}
- (void)restart{
if ([self isValid]) {
[self setFireDate:[NSDate date]];
}
}
- (void)restartAfterTimeInterval:(NSTimeInterval)interval{
if ([self isValid]) {
[self setFireDate:[NSDate dateWithTimeIntervalSinceNow:interval]];
}
}
- UIView (ForLMJEndlessLoopScrollView)
- (UIView *)copyView; // 復(fù)制一個相同的UIView
- (UIView *)copyView{
NSData * tempArchive = [NSKeyedArchiver archivedDataWithRootObject:self];
return [NSKeyedUnarchiver unarchiveObjectWithData:tempArchive];
}
代理
@protocol LMJEndlessLoopScrollViewDelegate <NSObject>
@required
// 要添加的內(nèi)容子視圖的個數(shù)
- (NSInteger)numberOfContentViewsInLoopScrollView:(LMJEndlessLoopScrollView *)loopScrollView;
// 每一個序號位置對應(yīng)的內(nèi)容子視圖(這個代理會調(diào)用很多次)
- (UIView *)loopScrollView:(LMJEndlessLoopScrollView *)loopScrollView contentViewAtIndex:(NSInteger)index;
@optional
// 滾動到當(dāng)前內(nèi)容子視圖的序號
- (void)loopScrollView:(LMJEndlessLoopScrollView *)loopScrollView currentContentViewAtIndex:(NSInteger)index;
// 點(diǎn)擊了某個內(nèi)容子視圖
- (void)loopScrollView:(LMJEndlessLoopScrollView *)loopScrollView didSelectContentViewAtIndex:(NSInteger)index;
@end
核心代碼
.h文件
@interface LMJEndlessLoopScrollView : UIView
@property (nonatomic,assign) id<LMJEndlessLoopScrollViewDelegate> delegate;
// 當(dāng)duration<=0時,默認(rèn)不自動滾動
- (id)initWithFrame:(CGRect)frame animationScrollDuration:(NSTimeInterval)duration;
- (void)reloadData;
@end
.m文件
#define SelfWidth_LMJ (self.frame.size.width)
#define SelfHeight_LMJ (self.frame.size.height)
@interface LMJEndlessLoopScrollView () <UIScrollViewDelegate>
{
UIScrollView * _scrollView;
NSInteger _totalPageCount;
NSInteger _currentPageIndex;
NSTimer * _animationTimer;
NSTimeInterval _animationDuration;
}
@end
@implementation LMJEndlessLoopScrollView
- (id)initWithFrame:(CGRect)frame animationScrollDuration:(NSTimeInterval)duration{
self = [super initWithFrame:frame];
if (self) {
[self initData];
[self initAnimationScrollTimerWithDuration:duration];
[self buildScrollView];
}
return self;
}
#pragma mark - Init
- (void)initData{
_animationTimer = nil;
_animationDuration = 0;
}
- (void)initAnimationScrollTimerWithDuration:(NSTimeInterval)duration{
_animationDuration = duration;
if (duration > 0) {
_animationTimer = [NSTimer scheduledTimerWithTimeInterval:duration
target:self
selector:@selector(startScroll:)
userInfo:nil
repeats:YES];
// 將timer加入到currentRunLoop中主要是防止在操作UI的時候影響到timer驅(qū)動的自動滾動
NSRunLoop *main = [NSRunLoop currentRunLoop];
[main addTimer:_animationTimer forMode:NSRunLoopCommonModes];
[_animationTimer pause];
}else{
/*
注意: 當(dāng) duration <= 0 時,_animationTimer為nil,由于在NSTimer擴(kuò)展的方法中進(jìn)行了空對象判斷,所以本頁代碼中都沒有進(jìn)行空判斷,也就是說此時對_animationTimer的操作都無效
*/
}
}
- (void)buildScrollView{
_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, SelfWidth_LMJ, SelfHeight_LMJ)];
_scrollView.delegate = self;
_scrollView.contentSize = CGSizeMake(SelfWidth_LMJ *3, SelfHeight_LMJ);
_scrollView.contentOffset = CGPointMake(SelfWidth_LMJ, 0);
_scrollView.pagingEnabled = YES;
_scrollView.showsHorizontalScrollIndicator = NO;
_scrollView.showsVerticalScrollIndicator = NO;
[self addSubview:_scrollView];
}
#pragma mark - Set
- (void)setDelegate:(id<LMJEndlessLoopScrollViewDelegate>)delegate{
_delegate = delegate;
/*
為什么要在delegate的set函數(shù)中reloadData,主要是因?yàn)樵趓eload的過程中需要調(diào)用代理獲取數(shù)據(jù)源,所以只有設(shè)置了代理之后才可以調(diào)用代理函數(shù)
*/
[self reloadData];
}
#pragma mark - ReloadData
- (void)reloadData{
_currentPageIndex = 0;
_totalPageCount = 0;
if ([self.delegate respondsToSelector:@selector(numberOfContentViewsInLoopScrollView:)]) {
_totalPageCount = [self.delegate numberOfContentViewsInLoopScrollView:self];
}else{
NSAssert(NO, @"請實(shí)現(xiàn)numberOfContentViewsInLoopScrollView:代理函數(shù)");
}
[self resetContentViews];
[_animationTimer restartAfterTimeInterval:_animationDuration];
}
#pragma mark - Methods
- (void)resetContentViews{
// 移除scrollView上的所有子視圖
[_scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
NSInteger previousPageIndex = [self getPreviousPageIndexWithCurrentPageIndex:_currentPageIndex];
NSInteger currentPageIndex = _currentPageIndex;
NSInteger nextPageIndex = [self getNextPageIndexWithCurrentPageIndex:_currentPageIndex];
UIView * previousContentView;
UIView * currentContentView;
UIView * nextContentView;
if ([self.delegate respondsToSelector:@selector(loopScrollView:contentViewAtIndex:)]) {
previousContentView = [self.delegate loopScrollView:self contentViewAtIndex:previousPageIndex];
currentContentView = [self.delegate loopScrollView:self contentViewAtIndex:currentPageIndex];
nextContentView = [self.delegate loopScrollView:self contentViewAtIndex:nextPageIndex];
NSArray * viewsArr = @[[previousContentView copyView],[currentContentView copyView],[nextContentView copyView]]; // copy操作主要是為了只有兩張內(nèi)容視圖的情況
for (int i = 0; i < viewsArr.count; i++) {
UIView * contentView = viewsArr[i];
[contentView setFrame:CGRectMake(SelfWidth_LMJ*i, 0, contentView.frame.size.width, contentView.frame.size.height)];
contentView.userInteractionEnabled = YES;
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapContentView:)];
[contentView addGestureRecognizer:tapGesture];
[_scrollView addSubview:contentView];
}
[_scrollView setContentOffset:CGPointMake(SelfWidth_LMJ, 0)];
}else{
// NSAssert(NO, @"請實(shí)現(xiàn)loopScrollView:contentViewAtIndex:代理函數(shù)");
}
}
// 獲取當(dāng)前頁上一頁的序號
- (NSInteger)getPreviousPageIndexWithCurrentPageIndex:(NSInteger)currentIndex{
if (currentIndex == 0) {
return _totalPageCount -1;
}else{
return currentIndex -1;
}
}
// 獲取當(dāng)前頁下一頁的序號
- (NSInteger)getNextPageIndexWithCurrentPageIndex:(NSInteger)currentIndex{
if (currentIndex == _totalPageCount -1) {
return 0;
}else{
return currentIndex +1;
}
}
#pragma mark - UIScrollView Delegate
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
// 當(dāng)手動滑動時 暫停定時器
[_animationTimer pause];
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
// 當(dāng)手動滑動結(jié)束時 開啟定時器
[_animationTimer restartAfterTimeInterval:_animationDuration];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
int contentOffsetX = scrollView.contentOffset.x;
if(contentOffsetX >= (2 * SelfWidth_LMJ)) {
_currentPageIndex = [self getNextPageIndexWithCurrentPageIndex:_currentPageIndex];
// 調(diào)用代理函數(shù) 當(dāng)前頁面序號
if ([self.delegate respondsToSelector:@selector(loopScrollView:currentContentViewAtIndex:)]) {
[self.delegate loopScrollView:self currentContentViewAtIndex:_currentPageIndex];
}
[self resetContentViews];
}
if(contentOffsetX <= 0) {
_currentPageIndex = [self getPreviousPageIndexWithCurrentPageIndex:_currentPageIndex];
// 調(diào)用代理函數(shù) 當(dāng)前頁面序號
if ([self.delegate respondsToSelector:@selector(loopScrollView:currentContentViewAtIndex:)]) {
[self.delegate loopScrollView:self currentContentViewAtIndex:_currentPageIndex];
}
[self resetContentViews];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
[scrollView setContentOffset:CGPointMake(SelfWidth_LMJ, 0) animated:YES];
}
#pragma mark - Action
- (void)startScroll:(NSTimer *)timer{
// 主要為了處理沒有滑完整頁的情況
CGFloat contentOffsetX = ( (int)(_scrollView.contentOffset.x +SelfWidth_LMJ) / (int)SelfWidth_LMJ ) * SelfWidth_LMJ;
CGPoint newOffset = CGPointMake(contentOffsetX, 0);
[_scrollView setContentOffset:newOffset animated:YES];
}
#pragma mark - TapAction
- (void)tapContentView:(UITapGestureRecognizer *)gesture{
if ([self.delegate respondsToSelector:@selector(loopScrollView:didSelectContentViewAtIndex:)]) {
[self.delegate loopScrollView:self didSelectContentViewAtIndex:_currentPageIndex];
}
}
使用
#import "LMJEndlessLoopScrollView.h"
@interface ViewController () <LMJEndlessLoopScrollViewDelegate>
{
NSMutableArray * _contentViewsDataArr;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
_contentViewsDataArr = [NSMutableArray array];
NSArray *colorArray = @[[UIColor cyanColor],[UIColor blueColor],[UIColor greenColor],[UIColor yellowColor],[UIColor purpleColor]];
for (int i = 0; i < 2; i++) {
UILabel *tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 280, 200)];
tempLabel.backgroundColor = colorArray[i];
tempLabel.textAlignment = NSTextAlignmentCenter;
tempLabel.text = [NSString stringWithFormat:@"%d",i];
tempLabel.font = [UIFont boldSystemFontOfSize:50];
[_contentViewsDataArr addObject:tempLabel];
}
LMJEndlessLoopScrollView * scrollView = [[LMJEndlessLoopScrollView alloc] initWithFrame:CGRectMake(20, 100, 280, 200) animationScrollDuration:3];
scrollView.delegate = self;
scrollView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:scrollView];
}
#pragma mark - LMJEndlessLoopScrollView Delegate
- (NSInteger)numberOfContentViewsInLoopScrollView:(LMJEndlessLoopScrollView *)loopScrollView{
return _contentViewsDataArr.count;
}
- (UIView *)loopScrollView:(LMJEndlessLoopScrollView *)loopScrollView contentViewAtIndex:(NSInteger)index{
return _contentViewsDataArr[index];
}
- (void)loopScrollView:(LMJEndlessLoopScrollView *)loopScrollView didSelectContentViewAtIndex:(NSInteger)index{
NSLog(@"----點(diǎn)擊-----%ld",index);
}
- (void)loopScrollView:(LMJEndlessLoopScrollView *)loopScrollView currentContentViewAtIndex:(NSInteger)index{
NSLog(@"----當(dāng)前-----%ld",index);
}
@end
github托管地址:
https://github.com/JerryLMJ/LMJEndlessLoopScrollView
如果此demo幫助到你,請賜給一顆star,你的鼓勵是我coding的動力
版權(quán)聲明:出自MajorLMJ技術(shù)博客的原創(chuàng)作品 ,轉(zhuǎn)載時必須注明出處及相應(yīng)鏈接!