简介
- 广告无限轮播图都很常见,创建三个
UIImageView
添加到就能达到无限轮播的效果(其实两张也可以,但是十分麻烦),本示例中有三种模式可以设定往左滚动,往右滚动,或者根据手动滑屏的方向随意改变其滚动的方向.并且不仅考虑到三张以上的图片轮播,也考虑了三张一下或者没有图片的情况.
原理
- 默认设置
UIScrollView
偏移量让中间的UIImageView
展示第一张图片. - 开启定时器时,如果设置的滚动标记是往左滚动,那么就在定时器事件中给右边的
UIImageView
设置当前图片的下一张图片,然后执行设置UIScrollView
的contentOffset
让右边的UIImageView
展示到屏幕中,当动画结束后把图片展示到中间的UIImageView
,造成轮播的假象;如果是往右滚动类似,设置上一张图片到左边的UIImageView
上,然后动画完成设置到中间的UIImageView
上,主要定时器代码如下:
- (void)changeOffset {
switch (self.scrollMode) {
case LeftScrollMode: {
[self scrollToLeft];
}
break;
case RightScrollMode:
[self scrollToRight];
break;
default:
[self scrollWithAutomaticMode];
break;
}
}
- (void)scrollWithAutomaticMode{
if(self.isToLeft){
[self scrollToLeft];
}else{
[self scrollToRight];
}
}
- (void)scrollToLeft {
_currentPage ++;
if (_currentPage >= _imagesNameArray.count) {
_currentPage = 0;
}
UIImageView *rightImageView = _imageViewsArray[2] ;
[rightImageView setImage:[UIImage imageNamed:_imagesNameArray[_currentPage]]];
[UIView animateWithDuration:_animationInterval animations:^{
_mainScrollView.contentOffset = CGPointMake(_widthOfView*2, 0);
} completion:^(BOOL finished) {
UIImageView * mainImageView = _imageViewsArray[1];
[mainImageView setImage:[UIImage imageNamed:_imagesNameArray[_currentPage]]];
_mainScrollView.contentOffset = CGPointMake(_widthOfView, 0);
}];
_imageViewPageControl.currentPage = _currentPage;
}
- (void)scrollToRight {
_currentPage --;
if (_currentPage < 0) {
_currentPage = _imagesNameArray.count-1;
}
UIImageView *leftImageView = _imageViewsArray[0] ;
[leftImageView setImage:[UIImage imageNamed:_imagesNameArray[_currentPage]]];
[UIView animateWithDuration:_animationInterval animations:^{
_mainScrollView.contentOffset = CGPointMake(0, 0);
} completion:^(BOOL finished) {
UIImageView * mainImageView = _imageViewsArray[1];
[mainImageView setImage:[UIImage imageNamed:_imagesNameArray[_currentPage]]];
_mainScrollView.contentOffset = CGPointMake(_widthOfView, 0);
}];
_imageViewPageControl.currentPage = _currentPage;
}
- 手动拖动时,由于RunLoop切换了模式,这时定时器将暂停,刚好我们可以处理拖动事件.将要拖动时会调用
UIScrollView
代理方法scrollViewWillBeginDragging
,这里面由于我们不知道是往左边拖动还是往右边拖动,所以要在这里设置左边和右边的UIImageView
对应当前展示图片的上一张图片和下一张图片.关键代码如下:
-(void) scrollViewWillBeginDragging:(UIScrollView *)scrollView{
UIImageView *leftImageView = _imageViewsArray[0] ;
NSInteger leftIndex = _currentPage - 1;
if (leftIndex < 0) {
leftIndex = _imagesNameArray.count - 1;
}
[leftImageView setImage:[UIImage imageNamed:_imagesNameArray[leftIndex]]];
UIImageView *rightImageView = _imageViewsArray[2] ;
NSInteger rightIndex = _currentPage + 1;
if (rightIndex >= _imagesNameArray.count) {
rightIndex = 0;
}
[rightImageView setImage:[UIImage imageNamed:_imagesNameArray[rightIndex]]];
}
- 手完成拽动,并停止滚动时会调用
scrollViewDidEndDecelerating
代理方法,这时可以根据偏移量判断是往左边滑动还是右边滑动了,如果是往左边滑动就将下一张图片设置到中间的UIImageView
上,并设置contentOffset
来展示中间的UIImageView
,造成左滑的假象;如果是往右边滑动则将上一张图片设置到中间的UIImageView
上,并设置contentOffset
来展示中间的UIImageView
,造成右滑的假象.滚动停止后Runloop会切回默认模式,定时器会立马重新工作,我们可以设置一个定时时间间隔后定时器重新开始工作,关键代码如下:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{
NSLog(@"%lf",scrollView.contentOffset.x);
if (scrollView.contentOffset.x == 0) {
_currentPage--;
if (_currentPage < 0) {
_currentPage = _imagesNameArray.count-1;
}
if (self.scrollMode == AutomaticMode){
self.toLeft = NO;
}
}
if (scrollView.contentOffset.x == _widthOfView * 2) {
_currentPage++;
if(_currentPage >= _imagesNameArray.count)
_currentPage = 0;
if (self.scrollMode == AutomaticMode){
self.toLeft = YES;
}
}
UIImageView *mainImagev = _imageViewsArray[1];
[mainImagev setImage:[UIImage imageNamed:_imagesNameArray[_currentPage]]];
self.mainScrollView.contentOffset = CGPointMake(_widthOfView, 0);
_imageViewPageControl.currentPage = _currentPage;
[self resumeTimer];
}
-(void)resumeTimer{
if (![_timer isValid]) {
_timer = nil;
return ;
}
[_timer setFireDate:[NSDate dateWithTimeIntervalSinceNow: self.timerInterval]];
}
- 其他一些就是一些细节要注意,如无限轮番时要防止脚标越界,设置向左或向右的标记,图片少于两张和没有图片时的处理,定时器循环引用的解除,已经定时器销毁的条件等等,具体可见demo.
相关demo示例