今天下午突然想起来上一次的面试经历,当时我是去面试美丽说IOS工程师,中午12点出发,2点就到了新中观大厦,没想到该公司是10:30上班,刚好人们吃午饭回来。笔试题很简单,半小时后一个姓赵的哥们来面试我。记得有一个问题是如何实现自动无限循环的UIScrollView。当时虽然思路想正确了,但还是回答的不够好。现在好好分析了一下网上开源的代码,有所收获,特此分享给大家。
无限循环:
我们都知道UIScrollView有一种很流畅的切换效果,结合UIPageControl的辅助展示效果,就可以完成一个很不错的产品介绍功能页面。那么像一些购物app中,商品展示页面无限滚动的效果是如何实现的呢?
方法1:前后+1方法,这也最常见的一种做法。假如我们有四张需要展示的图片,我们创建了一个数组来保存图片名字,此时数组中保存的是按顺序的1.png,2.png,3.png,4.png,这四个图片名字。要实现无限循环的效果,我们需要改动一下这个数组为:4.png,1.png,2.png,3.png,4.png,1.png,我们发现在原来数组的前后分别加入了一个图片名字,即将要循环展示的下一张图片的名字。当你滑动到4.png的时候,下一张会是1.png。当你在1.png往回滑动的时候,将要出现4.png。
好了,下面是我们的核心内容:我们发现目前数组中有6个图片,当我们从3.png滑动到4.png,又从4.png滑动到1.png的时候,我们要神不知鬼不觉的迅速切换到排在第二位的1.png。反向滑动的时候也是如此,从1.png滑动到4.png的时候,我们要神不知鬼不觉的切换到拍到倒数第二位的4.png。那么怎么样才能实现神不知鬼不觉呢?
看下面这两个UIScrollView的实例方法:
- (void)setContentOffset:(CGPoint)contentOffset animated:(BOOL)animated; - (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated;
这两个方法可以在animated参数为NO的时候,帮助我们迅速切换视图。
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;
此时我们来检测是否是滑动到了我们将要出发的1.png和4.png,如果是的话,那么就悄悄调用上面两个方法中的任意一个来实现视图切换。
实现代码如下所示:int currentPage = (int)self.scrollView.contentOffset.x/320; if (currentPage==0) { [self.scrollView scrollRectToVisible:CGRectMake(320 * [slideImages count]-2,0,320,460) animated:NO]; // 序号0,跳转到最后1页 } else if (currentPage==[slideImages count]-1) { [self.scrollView scrollRectToVisible:CGRectMake(320,0,320,460) animated:NO]; // 最后+1,循环第1页 }
方法2:瞒天过海。此方法中无论数据源有多少个,UIScrollView只保留其中三个视图,其实这是方法1的变种。当你滑动UIScrollView的时候,无非是向前滑动,或者是向后滑动,所以能够组成无限循环的基本条件就是前、中、后 三个视图。当你每次滑动的时候我都神不知鬼不觉的切换一下这三个视图。这也是和方法1 的最主要区别。
看看下面的区别:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)aScrollView { [_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width, 0) animated:YES]; }
- (void)scrollViewDidScroll:(UIScrollView *)aScrollView { int x = aScrollView.contentOffset.x; //往下翻一张 if(x >= (2*self.frame.size.width)) { [self loadData]; } //往上翻 if(x <= 0) { [self loadData]; } }
- (void)loadData { //从scrollView上移除所有的subview NSArray *subViews = [_scrollView subviews]; if([subViews count] != 0) { [subViews makeObjectsPerformSelector:@selector(removeFromSuperview)]; } for (int i = 0; i < 3; i++) { //只有3个视图 UIView *v = [_curViews objectAtIndex:i]; v.frame = CGRectOffset(v.frame, v.frame.size.width * i, 0); [_scrollView addSubview:v]; } [_scrollView setContentOffset:CGPointMake(_scrollView.frame.size.width, 0)]; }
自动无限循环
刚才讲解了无限循环的两种不同实现方法,下面来讲解一下如何让它自动滑动。我想大家都用过NSTimer,没错,用它来实现简单的计时器最好不过了。
在适当位置初始化一个NSTimer,设定3秒执行一次runTimePage()方法:
// 定时器 循环 [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(runTimePage) userInfo:nil repeats:YES];
在runTimePage()方法中,我们将要实现获取当前page页数,然后跳转到下一个page。
- (void)runTimePage { int page = pageControl.currentPage; // 获取当前的page page++; pageControl.currentPage = page > [slideImages count]-2 ? 0 : page ; [self.scrollView setContentOffset:CGPointMake(320*(page+1),0) animated:YES]; }
贴出几个参考demo地址,有兴趣的同学可以去看看。以上分析仅供参考。
demo1,demo2,demo3