欢迎下载:项目地址
网上这么多造好的轮子,为啥自己要去造个轮子?
其实自己在造轮子之前也看了网上的一些实现方案:
1. UIScrollView与N + 2个UIImageView
2. UIScrollView与1 + 2个UIImageView
3. UICollectionView与N乘以一个很大的数字,然后初始化的时候滚到中间位置
这些方案多多少少都会有一些问题:
方案一:如果有大量的图片需要显示就会造成内存的暴增,严重影响APP的性能
方案二:虽然不会造成内存暴增,但是实现起来也是比较繁琐,需要反复的调整各个UIImageView的位置,计算现在显示的是哪一个图片,代码体积较为庞大
方案三:主要的问题是实现不够优雅
下面说说我的实现
先说说为啥选用UICollectionView,它最大的一个优点就是cell的复用机制,这个机制保证了不论我需要显示多少张图片,它在内存中实际就创建两个cell
原理:返回N + 2个cell,indexPath.row == 0的cell展示最后一张图片,indexPath.row == N + 1的cell展示第一张图片,这样就形成了一个循环,当滚动到indexPath.row == 0时偏移到indexPath.row == N的cell;当滚动到indexPath.row == N + 1时偏移到indexPath.row == 1的cell
完整实现代码如下:
//
// DABannerView.m
// DABannerView
//
// Created by linfeng wang on 2019/7/22.
// Copyright © 2019 linfeng wang. All rights reserved.
//
#import "DABannerView.h"
#import "DABannerCollectionViewCell.h"
#import "DABannerFlowLayout.h"
#define random(r, g, b, a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)/255.0]
#define randomColor random(arc4random_uniform(256), arc4random_uniform(256), arc4random_uniform(256), arc4random_uniform(256))
@interface DABannerView ()<UICollectionViewDelegate,UICollectionViewDataSource>
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) UIPageControl *pageControl;
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation DABannerView {
NSArray <UIColor *>*_colorArr;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_colorArr = @[[UIColor redColor],[UIColor greenColor],[UIColor blueColor],[UIColor yellowColor]];
[self addSubview:self.collectionView];
[self addSubview:self.pageControl];
}
return self;
}
#pragma mark -- action
- (void)timerAction:(NSTimer *)timer {
NSIndexPath *indexPath = [self.collectionView indexPathsForVisibleItems].lastObject;
NSIndexPath *nextPath = [NSIndexPath indexPathForItem:(indexPath.item + 1)%(self.urlStringForImageArr.count+2) inSection:indexPath.section];
[self.collectionView scrollToItemAtIndexPath:nextPath atScrollPosition:UICollectionViewScrollPositionLeft animated:YES];
}
#pragma mark -- collectionView delegate and datasource
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.urlStringForImageArr.count + 2;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
DABannerCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"DABannerCollectionViewCell" forIndexPath:indexPath];
if (indexPath.row == 0) {
cell.backgroundColor = _colorArr.lastObject;
}else if (indexPath.row ==_urlStringForImageArr.count + 1) {
cell.backgroundColor = _colorArr.firstObject;
}else {
cell.backgroundColor = _colorArr[indexPath.row - 1];
}
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
}
#pragma mark -- scrollview delegate
- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView{
CGFloat offsetX = scrollView.contentOffset.x;
NSInteger page = offsetX / self.bounds.size.width;
NSInteger itemsCount = [self.collectionView numberOfItemsInSection:0];
if (page == 0) { // 第一页
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:self.urlStringForImageArr.count inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
} else if (page == itemsCount - 1) { // 最后一页
[self.collectionView scrollToItemAtIndexPath:[NSIndexPath indexPathForRow:1 inSection:0] atScrollPosition:UICollectionViewScrollPositionNone animated:NO];
}
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView*)scrollView{
// 手动调用减速完成的方法
[self scrollViewDidEndDecelerating:self.collectionView];
}
- (void)scrollViewDidScroll:(UIScrollView*)scrollView{
CGFloat offsetX = scrollView.contentOffset.x;
CGFloat page = offsetX / self.bounds.size.width;
NSInteger itemsCount = [self.collectionView numberOfItemsInSection:0];
if (page == 0) { // 第一页
self.pageControl.currentPage = self.urlStringForImageArr.count - 1;
} else if (page == itemsCount - 1) { // 最后一页
self.pageControl.currentPage = 0;
}else {
self.pageControl.currentPage = page - 1;
}
}
#pragma mark -- setter and getter
- (UICollectionView *)collectionView {
if (!_collectionView) {
DABannerFlowLayout *layout = [[DABannerFlowLayout alloc] init];
_collectionView = [[UICollectionView alloc] initWithFrame:self.frame collectionViewLayout:layout];
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.bounces = NO;
_collectionView.pagingEnabled = YES;
_collectionView.showsVerticalScrollIndicator = NO;
_collectionView.showsHorizontalScrollIndicator = NO;
_collectionView.dataSource = self;
_collectionView.delegate = self;
[_collectionView registerNib:[UINib nibWithNibName:@"DABannerCollectionViewCell" bundle:nil] forCellWithReuseIdentifier:@"DABannerCollectionViewCell"];
}
return _collectionView;
}
- (UIPageControl *)pageControl {
if (!_pageControl) {
CGFloat width = 120;
CGFloat height = 20;
CGFloat pointX = ([UIScreen mainScreen].bounds.size.width - width) / 2;
CGFloat pointY = self.bounds.size.height - height;
_pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(pointX, pointY, width, height)];
_pageControl.numberOfPages = self.urlStringForImageArr.count;
_pageControl.userInteractionEnabled = NO;
_pageControl.pageIndicatorTintColor = [UIColor lightTextColor];
_pageControl.currentPageIndicatorTintColor = [UIColor whiteColor];
}
return _pageControl;
}
- (void)setUrlStringForImageArr:(NSArray *)urlStringForImageArr {
_urlStringForImageArr = urlStringForImageArr;
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = urlStringForImageArr.count;
[self.collectionView reloadData];
//滚动到中间位置
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:1 inSection:0];
[self.collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];
_timer = [NSTimer timerWithTimeInterval:2 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSDefaultRunLoopMode];
_timer.fireDate = [NSDate dateWithTimeIntervalSinceNow:2];
}
@end