轮播图在开发中经常用到。并且面试的时候也经常回问道。
其实最长问道的也就两点
1、内存优化
2、计时器问题
3、轮播实现方案
此轮播图以UIScrollView实现
先以第一点内存优化和实现方案来讲,如何去做内存优化?
图片在iOS设备中很占内存,所以每当遇到加载图片的时候需要格外注意,不要去加载一些不必要的图片。
首先应当想到要减少UIImageView在UIScrollView上加载。结合UITableView的特点:复用。所以至少应当创建三个UIImageView。
实际上我们所展示的第1张图片在对应的ScrollView上应该是第2页。
并且重要的一点就是:所展示的图片一直是中间的。当滑到两边的图片后,要立刻重置到第二张。
两种代理实现方案
减速实现
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
滑动过程中
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
当使用结束拖拽的代理正常使用情况下其实是不会出现的问题的,但是当用户快速拖拽时,scrollview的偏移会出现问题。最好的方法便是实时计算偏移量
核心代码
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self reloadIndex];
}
//滑到中心,切记不能调用该动画,否则会触发代理
- (void)scrollCenter
{
[self.mainScrollView setContentOffset:CGPointMake(CGRectGetWidth(self.mainScrollView.bounds), 0)];
if (self.indexBack) {
self.indexBack(self.index);
}
}
//计算页数
- (void)reloadIndex
{
if (self.imageArray && self.imageArray.count > 0)
{
CGFloat pointX = self.mainScrollView.contentOffset.x;
//此处的value用于边缘判断,当imageview距离两边间距小于1时,触发偏移
CGFloat Value = 0.2f;
if (pointX > 2 * CGRectGetWidth(self.mainScrollView.bounds) - Value) {
self.index = (self.index + 1) % self.imageArray.count;
} else if (pointX < Value) {
self.index = (self.index + self.imageArray.count - 1) % self.imageArray.count;
}
}
}
//重写index的set方法
- (void)setIndex:(NSInteger)index
{
_index = index;
NSInteger totalCount = self.imageArray.count;
NSInteger leftIndex = (self.index+totalCount-1)%totalCount;
NSInteger rightIndex = (self.index+1)%totalCount;
[self.leftImageView setImage:[UIImage imageNamed:self.imageArray[leftIndex]]];
[self.midImageView setImage:[UIImage imageNamed:self.imageArray[self.index]]];
[self.rightImageView setImage:[UIImage imageNamed:self.imageArray[rightIndex]]];
[self scrollCenter];
}
关于计算页数说明:
假如有4张图片排序为,4|0|1|2|3,其实严格说此排序像一个环形数列,所以leftIndex和rightIndex的公式相当于去计算指定页数的前一个和后一个数字
.h 文件
@interface MCScrollView : UIView
@property (nonatomic, copy) void(^indexBack)(NSInteger pageIndex); //页数回调
@property (nonatomic, copy) NSArray *imageArray; //存储图片数据
@property (nonatomic, assign) NSInteger index; //当前第几页,默认为0(0为第一页,如果制定页数需要加1)
@end
定时器添加
.h文件添加
@property (nonatomic, assign) NSTimeInterval duration; //时长
实现
- (void)setDuration:(NSTimeInterval)duration
{
_duration = duration;
if (duration > 0.0) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:duration target:self selector:@selector(changeNext) userInfo:nil repeats:YES];
[self.timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:duration]];
}
}
- (void)changeNext
{
[self.mainScrollView setContentOffset:CGPointMake(2*CGRectGetWidth(self.mainScrollView.bounds), 0) animated:YES];
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
[self.timer setFireDate:[NSDate distantFuture]];
//[NSDate distantFuture]表示暂停计时
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self.timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:self.duration]];
//
}
[NSDate dateWithTimeIntervalSinceNow:self.duration]表示在当前时间的几秒后开始计时,优点是不会立即执行计时器
Demo地址:https://github.com/HeartbeatT/MCScrollView.git