iOS界面上经常见到无限轮播图,n张图片轮流播放。 下面给出一个解决方案和demo(https://github.com/zhengwenming/WMBannerView)。 demo可设定轮播时间,可轮播本地和网络图片(可设置默认的placeholder),支持手动和自动无限循环轮播。 思路是这样的,我们做一个WMBannerView继承UIView,给出初始化方法, -(instancetype)initWithFrame:(CGRect)frame withURLArrayOrImagesArray:(NSArray *)dataArray; 这个初始化方法会传进去一个数组,这个数组里面可以放本地的UIImage对象,也可以放网络上图片的URL。这个WMBannerView里面有一个UIScrollView,用这个UIScrollView去不断的加载上中下这三个imageView。到达最后一个iamge的时候,再滑动就加载第一个,如果反过来滑动到第一个图片,再滑动,就加载最后一个ImageView。具体的看代码实现。 .h文件里的代码: #import < UIKit/UIKit.h>
typedef NS_ENUM(NSInteger,WMPageContolAlignment) { WMPageContolAlignmentCenter, /*< 滚动点居中 / /* */ WMPageContolAlignmentRight, /*< 滚动点居右 / /* */ WMPageContolAlignmentNone /*< 滚动点隐藏 / };
typedef void(^TapActionBlock)(NSInteger index);
@interface WMBannerView : UIView
/* 播放周期,默认五秒钟 如设置0则不播放 */ @property(nonatomic,assign)NSTimeInterval animationDuration; /* 滚动点对齐方式,默认居中 */ @property(nonatomic,assign)WMPageContolAlignment pageControlAlignment;
/* 默认图片,下载未完成时显示 网络图片的时候设置*/ /* 注意:赋值必须写在Start方法之前,否则仍然为nil */ @property(nonatomic,strong)UIImage *placeHoldImage;
/* 数据源 **/ @property(nonatomic,copy)NSArray *dataArray;
/** * 初始化广告播放滚动View * * @param rect 尺寸位置 * @param dataArray 图片数据源 */ -(instancetype)initWithFrame:(CGRect)frame withURLArrayOrImagesArray:(NSArray *)dataArray; /** * 开始播放,默认五秒钟,点击响应block回调 * * @param block 回调,返回当前图片index,不需要回调则设置为nil */ - (void)startWithTapActionBlock:(TapActionBlock)block;
/** * 停止播放 */ - (void)stop; @end
再看.m实现文件里面的代码 依赖库为SDWebImage #import “UIImageView+WebCache.h” #import “WMBannerView.h”
@interface WMBannerView () //容器 @property(nonatomic,strong)UIScrollView *scrollView; /* 滚动圆点 **/ @property(nonatomic,strong)UIPageControl *pageControl; /* 定时器 **/ @property(nonatomic,strong)NSTimer *animationTimer; /* 当前index **/ @property(nonatomic,assign)NSInteger currentPageIndex; /* 所有的图片数组 **/ @property(nonatomic,strong)NSMutableArray *imageArray; /* 当前图片数组,永远只存储三张图 **/ @property(nonatomic,strong)NSMutableArray *currentArray; /* block方式接收回调 */ @property(nonatomic,copy)TapActionBlock block; @end
@implementation WMBannerView
-(instancetype)initWithFrame:(CGRect)frame withURLArrayOrImagesArray:(NSArray *)dataArray{ self = [super initWithFrame:frame]; if (self) { self.dataArray = dataArray; self.autoresizesSubviews = YES; self.scrollView = [[UIScrollView alloc] initWithFrame:self.bounds]; self.scrollView.contentMode = UIViewContentModeCenter; self.scrollView.contentSize = CGSizeMake(3 *frame.size.width, frame.size.height); self.scrollView.delegate = self; self.scrollView.contentOffset = CGPointMake(frame.size.width, 0); self.scrollView.pagingEnabled = YES; self.scrollView.showsHorizontalScrollIndicator = NO; self.scrollView.showsVerticalScrollIndicator = NO; [self addSubview:self.scrollView];
//设置分页显示的圆点 _pageControl = [[UIPageControl alloc] init]; _pageControl.alpha = 0.8; _pageControl.currentPageIndicatorTintColor = [UIColor redColor]; _pageControl.pageIndicatorTintColor = [UIColor whiteColor]; [self addSubview:_pageControl]; //点击事件 UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap)]; [self addGestureRecognizer:tapGesture]; //默认五秒钟循环播放 self.animationDuration = 5; //默认居中 self.pageContolAliment = WMPageContolAlignmentCenter; //默认第一张 self.currentPageIndex = 0; } return self;}
-(void)layoutSubviews{ [super layoutSubviews]; self.scrollView.frame = self.bounds; }
-(void)setPageContolAliment:(WMPageContolAlignment)pageContolAliment{ _pageControlAlignment = pageContolAliment; _pageControl.hidden = NO; switch (pageContolAliment) { case WMPageContolAlignmentCenter: { _pageControl.frame = CGRectMake(0, CGRectGetHeight(self.scrollView.frame) - 20, CGRectGetWidth(self.scrollView.frame), 10); } break; case WMPageContolAlignmentRight: { CGSize size = CGSizeMake(self.dataArray.count * 10 * 1.2, 10); CGFloat x = self.scrollView.frame.size.width - size.width - 10; CGFloat y = self.scrollView.frame.size.height - 20; _pageControl.frame = CGRectMake(x, y, size.width, size.height); } break; case WMPageContolAlignmentNone: _pageControl.hidden = YES; break;
default: break; }}
-(void)setAnimationDuration:(NSTimeInterval)animationDuration{ _animationDuration = animationDuration;
[self.animationTimer invalidate]; self.animationTimer = nil; if (animationDuration <= 0) { return; } self.animationTimer = [NSTimer scheduledTimerWithTimeInterval:_animationDuration target:self selector:@selector(animationTimerDidFired:) userInfo:nil repeats:YES]; [self.animationTimer setFireDate:[NSDate distantFuture]];}
-(void)downLoadImage{ if (self.dataArray && self.dataArray.count > 0) { if ([self.dataArray.firstObject respondsToSelector:@selector(hasPrefix:)]) { if ([self.dataArray.firstObject hasPrefix:@”http”]) {//网络图片 self.imageArray = [NSMutableArray array]; __weak typeof(self) weak = self; [self.dataArray enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.scrollView.frame]; [imageView sd_setImageWithURL:[NSURL URLWithString:obj] placeholderImage:self.placeHoldImage]; [weak.imageArray addObject:imageView]; }]; _pageControl.numberOfPages = self.dataArray.count; [self configContentViews];
} } else{//本地图片 self.imageArray = [NSMutableArray array]; __weak typeof(self) weak = self; [self.dataArray enumerateObjectsUsingBlock:^(UIImage * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { UIImageView *imageView = [[UIImageView alloc]initWithFrame:self.scrollView.frame]; imageView.image = obj; [weak.imageArray addObject:imageView]; }]; _pageControl.numberOfPages = self.dataArray.count; [self configContentViews]; } }}
#pragma mark - 私有函数
(void)configContentViews { [self.scrollView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
NSInteger previousPageIndex = [self getValidNextPageIndexWithPageIndex:_currentPageIndex - 1]; NSInteger rearPageIndex = [self getValidNextPageIndexWithPageIndex:_currentPageIndex + 1];
self.currentArray = (_currentArray?:[NSMutableArray new]);
_currentArray.count == 0 ?:[_currentArray removeAllObjects];
if (_imageArray) { if (_imageArray.count >= 3) { [_currentArray addObject:_imageArray[previousPageIndex]]; [_currentArray addObject:_imageArray[_currentPageIndex]]; [_currentArray addObject:_imageArray[rearPageIndex]]; } else{ [self getImageFromArray:_imageArray[previousPageIndex]]; [self getImageFromArray:_imageArray[_currentPageIndex]]; [self getImageFromArray:_imageArray[rearPageIndex]]; } }
[_currentArray enumerateObjectsUsingBlock:^(UIImageView * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { obj.userInteractionEnabled = YES; CGRect rightRect = obj.frame; rightRect.origin = CGPointMake(CGRectGetWidth(self.frame) * idx, 0); obj.frame = rightRect; [self.scrollView addSubview:obj]; }];
[self.scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.scrollView.frame), 0)]; }
(NSInteger)getValidNextPageIndexWithPageIndex:(NSInteger)currentPageIndex; { if(currentPageIndex == -1){ return self.dataArray.count - 1; } else if (currentPageIndex == self.dataArray.count){ return 0; } else return currentPageIndex; }
/** * 解决小于三个图片显示的bug * @param imageView 原始图 */ -(void)getImageFromArray:(UIImageView *)imageView{ //开辟自动释放池 @autoreleasepool { UIImageView *tempImage = [[UIImageView alloc]initWithFrame:imageView.frame]; tempImage.image = imageView.image; [_currentArray addObject:tempImage]; } }
#pragma mark - UIScrollViewDelegate(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { [self.animationTimer setFireDate:[NSDate distantFuture]]; }
(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate { [self.animationTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:self.animationDuration]]; }
(void)scrollViewDidScroll:(UIScrollView *)scrollView { int contentOffsetX = scrollView.contentOffset.x; if(contentOffsetX >= (2 * CGRectGetWidth(scrollView.frame))) { self.currentPageIndex = [self getValidNextPageIndexWithPageIndex:self.currentPageIndex + 1]; _pageControl.currentPage = _currentPageIndex; [self configContentViews]; } if(contentOffsetX <= 0) { self.currentPageIndex = [self getValidNextPageIndexWithPageIndex:self.currentPageIndex - 1]; _pageControl.currentPage = _currentPageIndex; [self configContentViews]; }
}
(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { [scrollView setContentOffset:CGPointMake(CGRectGetWidth(scrollView.frame), 0) animated:YES]; }
(void)animationTimerDidFired:(NSTimer *)timer { CGPoint newOffset = CGPointMake(self.scrollView.contentOffset.x + CGRectGetWidth(self.scrollView.frame), self.scrollView.contentOffset.y); [self.scrollView setContentOffset:newOffset animated:YES]; }
(void)tap { if (self.block) { self.block(self.currentPageIndex); } }
-(void)startWithTapActionBlock:(TapActionBlock)block{ [self.animationTimer setFireDate:[NSDate date]];
[self downLoadImage];
self.block = block; }
-(void)stop{ [self.animationTimer invalidate]; }
(void)dealloc { self.animationTimer = nil; self.imageArray = nil; self.dataArray = nil; self.scrollView = nil; }
@end
那么做好我们的轮播图WMBannerView了,现在开始用了
/* 网络图片测试 */ NSArray *URLArray = @[@”http://farm2.staticflickr.com/1709/24157242566_98d0192315_m.jpg“, @”http://farm2.staticflickr.com/1715/23815656639_ef86cf1498_m.jpg“, @”http://farm2.staticflickr.com/1455/23888379640_edf9fce919_m.jpg“];
WMBannerView * wmView = [[WMBannerView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.width*3/4) withURLArrayOrImagesArray:URLArray]; wmView.pageControlAlignment = WMPageContolAlignmentCenter; wmView.placeHoldImage = [UIImage imageNamed:@”placeholderImage”]; wmView.animationDuration = 1.0;//设置滚动的时间间隔,为0的时候不自动滚动 //点击图片的回调block,可以知道点击的index [wmView startWithTapActionBlock:^(NSInteger index) { NSLog(@”点击了第%@张”,@(index)); }];
然后放置到tableView的tableHeaderView上面
table = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) style:UITableViewStylePlain]; table.dataSource = self; table.delegate = self; table.tableHeaderView = wmView; table.tableFooterView = [UIView new]; [self.view addSubview:table];
https://github.com/zhengwenming/WMBannerView 描述:强大的广告轮播图,可设定轮播时间,可轮播本地和网络图片(可设置默认的placeholder),支持手动和自动无限循环轮播。可放到UITableView头上,也可以放置到UICollectionView的头上。
