老赖本来说要更新iOS学习课程,可走神弄了一下午的轮播图,这里把整个过程记录下来吧,对有需要的好朋友,或许有点儿小小的帮助.
首先说,轮播图,这个东西,做开发的应该都会,不过实现的的逻辑思路有所不同.
比方说固定有5张图,最基本的实现方法就是,在scrollView上添加7张图片,排列方式是:
五一二三四五一
注意这里的跳,不能开启动画.同理,当scrollView滑到最后一个,让它瞬间跳到左边的”一”这张上去…这样就实现了无限循环滚动.
这个方法,非常巧妙,平面理解有点儿费劲,不过老赖理解之—>你拿张纸条,让它收尾相连,形成一个空间的圆圈闭环,这样,估计你瞬间里明白了这个瞬间跳转是怎么回事了!
看了上面的效果图后,问题也就出来了,这里有少量的图片,可以直接把图片的imageView加载到scrollView上.但是,如果图片多呢,50张?100张?创建100个imageView加到scrollView上,内存也吃不消吧.
对了,有好朋友,应该想到了,可以用–复用机制!
复用机制的好处,在tableView用的淋漓尽致,做轮播图,咱们用它的亲戚,collectionView.因为系统空间本身就有复用机制,无论你加载多少照片,它只创建了两个cell,这样就大大的优化APP性能.
具体的详情,老赖这里不详细阐述了,照旧贴出相关链接:
http://www.cnblogs.com/wendingding/p/3890850.html
http://www.cnblogs.com/wendingding/p/3890953.html
这两篇是有关collectionView做轮播图的,当然,这是大神的系列,好朋友们,可以翻看前后篇,系统的学习一下.
一张图片压着另一张图片上面,这个效果在iPhone里就有,好像是调用系统相册里面切换照片时候的效果.
另外,重点来了!!!无论你多少张照片,老赖我这里只有用了两个UIImageView!没错,就是两个,一样完成无限轮播!
这个*不能装过咯,老赖我还是低调的,其实思路也很清晰,接下来,就听有北京著名赖人—-老赖娓娓道来之:
首先咱们还是先声明一些属性
//滚动视图
@property (nonatomic, strong) UIscrollView *scrollView;
//第一个图片
@property (nonatomic, strong) UIImageView *firstImageView;
//第二个图片
@property (nonatomic, strong) UIImageView *secondImageView;
//图片的数据源
@property (nonatomic, strong) NSMutableArray *imageDataSource;
//页面控制器
@property (nonatomic, strong) UIPageControl *pageController;
//时间控制器
@property (nonatomic, strong) NSTimer *timer;
有好朋友打眼一看,就知道老赖不专业了,整两张图片的ImageView,命名竟然用first和second这low的名字.好吧,老赖承认,时间紧,任务重,各种原因吧,总之就这样了,爱咋咋地,跟老赖讲道理,嗯哼?
接下来就是对对象的初始化,老赖给代码都注释了
//添加滚动视图
UIscrollView *scrollView = [[UIscrollView alloc] initWithFrame:self.bounds];
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.pagingEnabled = YES;
scrollView.contentOffset = CGPointMake(CGRectGetWidth(self.frame), 0);
scrollView.delegate = self;
scrollView.contentSize = CGSizeMake(CGRectGetWidth(self.frame) * 3, CGRectGetHeight(self.frame));
//添加点击事件
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapClick:)];
[scrollView addGestureRecognizer:tap];
//添加到父视图上
[self addSubview:scrollView];
self.scrollView = scrollView;
//给滚动视图添加两个UIImageView
UIImageView *firstImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
self.firstImageView = firstImageView;
UIImageView *secondImageView = [[UIImageView alloc] initWithFrame:self.bounds];
self.secondImageView = secondImageView;
[self.scrollView addSubview:secondImageView];
[self.scrollView addSubview:firstImageView];
//先设置第一张图片的位置,在滚动视图的正中央
self.firstImageView.frame = CGRectMake(CGRectGetWidth(self.frame), 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));
//设置pageController(这里可以根据个人喜好自定义)
UIPageControl *pageController = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), 20)];
pageController.center = CGPointMake(CGRectGetWidth(self.frame) / 2, CGRectGetHeight(self.frame) - 20);
//设置pageController 的页数
pageController.numberOfPages = self.imageDataSource.count;
pageController.currentPage = 0;
[self addSubview:pageController];
self.pageController = pageController;
其实老赖不喜欢,贴这么多代码…好多好朋友都跟老赖一样,代码一多,看不下去.那老赖我就把重要部分的代码,简短的贴出来,并解释说明之,最后,会把源码地址贴出来.
这里要说明一下刚才那一长串代码,scrollView的contentSize是3个屏幕宽,并且初始让scrollView的可视部分在最中间, 正好可以用来左右滚动.
然后,第一张图片的放到最中间,并且,它的位置是固定的,也就是说,第一张图片跟随scrollView滚动.
那第二张图片,就扮演滑动图片后,将要出现的视图了.
首先假定我们手指,从左往右滑动,也就是看看左边的图片,就是上一张图片:
//添加将要出现的视图(其实就是第二张图片)的中心点X坐标
static float nextImageViewCenterX = 0.f;
//判断滚动方向
if (scrollView.contentOffset.x < CGRectGetWidth(self.frame)) {
//从左往右
nextImageViewCenterX = (CGRectGetWidth(self.frame) + offsetX) / 2;
_nextImageIndex = _currentImageIndex - 1;
}
GPoint center = CGPointMake(nextImageViewCenterX , CGRectGetHeight(self.frame)/2);
//实时更新第二张图片的位置
self.secondImageView.center = center ;
But!!真的是老赖上面说的那样吗?其实不是!不要轻易相信老赖!
之所以说不是,是因为假设第一张图片往右走,如果你让第二张图片也往右走,松开手后,效果完全不是这样.这里其实是让第二张图像左走.
对,相对于scrollView来说,第二章图片要向左走!为什么呢?因为整个scrollView都向右走,松手后,scrollView的可视位置,由中间变成了最左边,此时只有让第二章图片也出现在最左边也能完全展示出来它.第二张图片的初始位置是在一半屏幕宽度上的,所以它要往左走到零!
接着来说,图片加载相关.之前声明了如下的成员变量:
//记录当前图片下标
int _currentImageIndex;
//记录下一张图片下标
int _nextImageIndex;
self.secondImageView.image = self.imageDataSource[_nextImageIndex];
if (_nextImageIndex == -1) {
_nextImageIndex = (int)self.imageDataSource.count - 1;
}else if (_nextImageIndex == self.imageDataSource.count){
_nextImageIndex = 0;
}
// 减速完成(分页滑动是会减速的)
- (void)scrollViewDidEndDecelerating:(UIscrollView *)scrollView
{
[self endRollscrollViewWith:scrollView];
}
// 滑动动画结束 setContentOffset: animated:YES 动画结束调用
- (void)scrollViewDidEndScrollingAnimation:(UIscrollView *)scrollView{
[self endRollscrollViewWith:scrollView];
}
//结束滚动后,重置页面
-(void)endRollscrollViewWith:(UIscrollView *)scrollView
{
//判断是否完成翻页
if (scrollView.contentOffset.x != CGRectGetWidth(self.frame)) {
//更新当前图片下标
_currentImageIndex = _nextImageIndex;
//给第一张相框添加图片
self.firstImageView.image = self.imageDataSource[_currentImageIndex];
//让视图瞬间回到中间位置
[self.scrollView setContentOffset:CGPointMake(CGRectGetWidth(self.frame), 0)];
//更新page
self.pageController.currentPage = _currentImageIndex;
}
}
下面讲的是一些基本用法,demo里面的用例已经足够了,聪明的好朋友们,不用往下看了,帅的小伙伴们继续跟着老赖往下走吧!
先说说协议代理封装的:
@property (nonatomic, assign) id delegate;
@property (nonatomic, assign) id dataSource;
//@required
//给轮播视图提供数据源数组
- (NSArray *)imagesArrayForWSWscrollView:(WSWscrollView *)scrollView;
//@optional
//点击事件回调
- (void)wswScroView:(WSWscrollView *)scrollView didSelectRowAtIndexPath:(NSInteger)index;
再来说说Block封装的:
/**
* 传入照片,并返回图片点击的回调block
*
* @param imagesArray 传入本地图片或者网络图片
* @param currentImageClickBlock 图片点击的block方法
*/
- (void)addImagesArray:(NSArray *)imagesArray currentImageClick:(CurrentImageClick)currentImageClickBlock;
//调用方法-->就是直接创建一个对象
WSWscrollView *scrollView = [[WSWscrollView alloc] initWithFrame:self.view.bounds];
/*
时间间隔一定要写在调用下面方法之前,因为方法里调用了创建时间控制器,
之后再设置间隔时间的话,就没有作用了
*/
scrollView.timeInterval = 1.f;
NSArray *array = @[@"火影01",@"火影02",@"火影03",@"火影04",];
//传入图片源数组并且实现回调block方法
[scrollView addImagesArray:array currentImageClick:^(NSInteger index) {
NSLog(@"--->我点的这是第%ld张图片",(long)index);
}];
//添加带父视图上
[self.view addSubview:scrollView];