- 浏览: 548175 次
文章分类
最新评论
-
lg70124752:
你好,你这个在数据量大的情况下正常吗,我写了一个类似的功能,在 ...
【Hadoop】MapReduce使用combiner优化性能 -
20131007:
维护这么多的博客,不累?
『开源』也顺手写一个 科学计算器:重磅开源 -
leaow567:
写的不错,条理清晰!
Android Service完全解析,关于服务你所需知道的一切(上)
UIScrollView用法
UIScrollView是iphone中的一个重要的视图,它提供了一个方法,让你在一个界面中看到所有的内容,从而不必担心因为屏幕的大小有限,必须翻到下一页进行阅览。确实对于用户来说是一个很好的体验。但是又是如何把所有的内容都加入到scrollview,是简单的addsubView。假如是这样,岂不是scrollView界面上要放置很多的图形,图片。移动设备的显示设备肯定不如PC,怎么可能放得下如此多的视图。所以在使用scrollView中一定要考虑这个问题,当某些视图滚动出可见范围的时候,应该怎么处理,是不管它那,还是进行内存回收或者重利用。苹果公司的UITableView就很好的展示了在UIScrollView中如何重用可视的空间,减少内存的开销。
首先还是看官方API如何解释UIScrollView,一下是翻译官方UIScrollView的帮助文档。
UIScrollView类支持显示比屏幕更大的应用窗口的内容。它通过挥动手势,能够使用户滚动内容,并且通过捏合手势缩放部分内容。
UIScrollView是UITableView和UITextView的超类。
UIScrollView的核心理念是,它是一个可以在内容视图之上,调整自己原点位置的视图。它根据自身框架的大小,剪切视图中的内容,通常框架是和应用程序窗口一样大。一个滚动的视图可以根据手指的移动,调整原点的位置。展示内容的视图,根据滚动视图的原点位置,开始绘制视图的内容,这个原点位置就是滚动视图的偏移量。ScrollView本身不能绘制,除非显示水平和竖直的指示器。滚动视图必须知道内容视图的大小,以便于知道什么时候停止;一般而言,当滚动出内容的边界时,它就返回了。
某些对象是用来管理内容显示如何绘制的,这些对象应该是管理如何平铺显示内容的子视图,以便于没有子视图可以超过屏幕的尺寸。就是当用户滚动时,这些对象应该恰当的增加或者移除子视图。
因为滚动视图没有滚动条,它必须知道一个触摸信号是打算滚动还是打算跟踪里面的子视图。为了达到这个目的,它临时中断了一个touch-down的事件,通过建立一个定时器,在定时器开始行动之前,看是否触摸的手指做了任何的移动。假如定时器行动时,没有任何的大的位置改变,滚动视图就发送一个跟踪事件给触摸的子视图。如果在定时器消失前,用户拖动他们的手指足够的远,滚动视图取消子视图的任何跟踪事件,滚动它自己。子类可以重载touchesShouldBegin:withEvent:inContentView:,pagingEnabled,和touchesShouldCancelInContentView:方法,从而影响滚动视图的滚动手势。
一个滚动视图也可以控制一个视图的缩放和平铺。当用户做捏合手势时,滚动视图调整偏移量和视图的比例。当手势结束的时候,管理视图内容显示的对象,就应该恰当的升级子视图的显示。当手势在处理的过程中,滚动视图不能够给子视图,发送任何跟踪的调用。
UIScrollView类有一个delegate,需要适配的协议是UIScrollViewDelegate。为了缩放和平铺工作,代理必须实现viewForZoomingInScrollView:和scrollViewDidEndZooming:withView:atScale:方法。另外,最大和最小缩放比例应该是不同的。
重要的提示:在UIScrollView对象中,你不应该嵌入任何UIWebView和UITableView。假如这样做,会出现一些异常情况,因为2个对象的触摸事件可能被混合,从而错误的处理。
这些都是官方API的解释,重点是理解UIScrollView怎么来控制手势的。可以由canCancelContentTouches这个方法的运用来解释UIScrollView如何控制手势的。
假如你设置canCancelContentTouches为YES,那么当你在UIScrollView上面放置任何子视图的时候,当你在子视图上移动手指的时候,UIScrollView会给子视图发送touchCancel的消息。而如果该属性设置为NO,ScrollView本身不处理这个消息,全部交给子视图处理。
那么这里就有疑问了,既然该属性设置未来NO了,那么岂不是UIScrollView不能处理任何事件了,那么为何在子视图上快速滚动的时候,UIScrollView还能移动那。这个一定要区分前面所说的UIScrollView中断touch-Down事件,开启一个定时器。我们设置的这个cancancelContentTouches属性为NO时,只是让UIScrollView不能发送cancel事件给子视图。而前面所说的时,中断touch-down事件,和取消touch事件是俩码事,所以当快速在子视图上移动的时候,当然可以滚动。但是如果你慢速的移动的话,就可以区分这个属性了,假如设定为YES,在子视图上慢速移动也可以滚动视图,但是如果为NO。因为UIScrollView,发送了cancel事件给子视图处理了,自己当然滚动不了了。
事件处理看过了,就要考虑scrollView如何重用内存的,下面写了一个例子模仿UITableView的重用的思想,这里只是模仿,至于苹果公司怎么实现这种重用的,他们应该有更好的方法。
这里的例子是在scrollView上放置4个2排2列的视图,但是内存中只占用6个视图的内存空间。当scrollView滚动的时候,通过不停的重用之前视图的内存空间,从而达到节省内存的效果。重用的方法如下:
1.如果scrollView向下面滚动,一旦一排视图滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,也就是改变位置到达末尾,达到重用的效果。
2.如果scrollView向上面滚动,一旦最末排的视图view滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,移动到最前面。
下面就需要在你创建的视图控制器中,创建一个重用的视图数组,用来把这些要显示的视图放入内存中,这里虽然界面上显示的是2排2列的四个视图,但是当拖动的时候,可能出现前面一排的视图显示一部分,末尾一排的视图显示一部分的情况,所以重用的数组中要放置6个视图。下面是定义的一些宏:
- #definesMyViewTotal6
- #definesMyViewWidth150
- #definesMyViewHeight220
- #definesMyViewGap10
具体实现代码如下:
- _aryViews=[[NSMutableArrayalloc]init];
- for(inti=0;i<sMyViewTotal;i++){
- CGFloatx;
- if(i%2){
- x=sMyViewWidth+sMyViewGap+sMyViewGap/2;
- }
- else{
- x=sMyViewGap/2;
- }
- CGFloaty=(sMyViewHeight+sMyViewGap)*(i/2);
- MyView*myView=[[MyViewalloc]initWithFrame:CGRectMake(x,y,sMyViewWidth,sMyViewHeight)];
- myView.showNumber=i;
- [myScrollViewaddSubview:myView];
- [_aryViewsaddObject:myView];
- [myViewrelease];
- }
所以这里的核心方法是,首先要判断是向上滚动还是向下滚动方法如下:
- -(void)scrollViewDidScroll:(UIScrollView*)scrollView{
- BOOLdirectDown;
- if(previousOffSet.y<scrollView.contentOffset.y){
- directDown=YES;
- }
- else{
- directDown=NO;
- }
- previousOffSet.y=scrollView.contentOffset.y;
- //防止最开始就向上面拖动的时候,改变数组视图树的位置。
- if(scrollView.contentOffset.y<0){
- return;
- }
- if(directDown){
- NSLog(@"down");
- MyView*subView=[_aryViewsobjectAtIndex:firstViewIndex];
- CGFloatfirstViewYOffset=subView.frame.origin.y+subView.frame.size.height+sMyViewGap;
- //寻找第一个视图是否滚动出去
- if(firstViewYOffset<scrollView.contentOffset.y){
- //改变数组中第一排可见视图的位置。
- [selfmoveIndexInViewsWithDirect:YES];
- }
- }
- else{
- NSLog(@"up");
- MyView*subView=[_aryViewsobjectAtIndex:(firstViewIndex+sMyViewTotal-2)%sMyViewTotal];
- CGFloatlastViewYOffset=subView.frame.origin.y-scrollView.bounds.size.height;
- if(lastViewYOffset>scrollView.contentOffset.y){
- [selfmoveIndexInViewsWithDirect:NO];
- }
- }
- }
每次滚动的时候先判断滚动位置即offset,和先前的比较。如果先前的大就是向下滚动,否则就是向上滚动。
找到了向下滚动了,就该判断是否子视图已经离开了可视范围。方法就是判断当前offset和视图的位置进行比较。如果判断滚到离开了可视范围,然后就是要改变重用视图数组中第一个视图的位置了。这里用了firstViewIndex来记录scrollView中第一个可见视图的位置,循环使用这6个视图达到重用的目的。自然firstViewIndex上面的一个视图就是最后一个视图的位置(firstViewIndex+sMyViewTotal-1)%sMyViewTotal。所以这里需要改变重用视图中firstViewIndex即第一个可见视图的位置。代码如下:
- -(void)moveIndexInViewsWithDirect:(BOOL)forward{
- [UIViewsetAnimationsEnabled:NO];
- if(forward){
- for(inti=firstViewIndex;i<(firstViewIndex+2);i++){
- MyView*subView=[_aryViewsobjectAtIndex:i%sMyViewTotal];
- subView.showNumber=subView.showNumber+sMyViewTotal;
- subView.frame=CGRectMake(subView.frame.origin.x,subView.frame.origin.y+(sMyViewTotal/2)*(sMyViewHeight+sMyViewGap),subView.frame.size.width,subView.frame.size.height);
- }
- firstViewIndex=(firstViewIndex+2)%sMyViewTotal;
- }
- else{
- intlastViewIndex=firstViewIndex+sMyViewTotal-1;
- for(inti=lastViewIndex;i>(lastViewIndex-2);i--){MyView*subView=[_aryViewsobjectAtIndex:(firstViewIndex+sMyViewTotal-i)%sMyViewTotal];
- subView.showNumber=subView.showNumber-sMyViewTotal;
- subView.frame=CGRectMake(subView.frame.origin.x,subView.frame.origin.y-(sMyViewTotal/2)*(sMyViewHeight+sMyViewGap),subView.frame.size.width,subView.frame.size.height);
- }
- firstViewIndex=(firstViewIndex+sMyViewTotal-2)%sMyViewTotal;
- }
- [UIViewsetAnimationsEnabled:YES];
- }
这里创建的子视图数字属性,是用来在视图上画数字的,这样就可以看到视图重用的效果了,应该是从0开始到无穷多,但是实际上内存中就创建了6个视图。
- -(void)drawRect:(CGRect)rect
- {
- //Drawingcode
- NSString*text=[NSStringstringWithFormat:@"%d",showNumber];
- [[UIColorredColor]set];
- [textdrawInRect:CGRectMake(rect.origin.x,rect.origin.y+rect.size.height/2-30,rect.size.width,30)withFont:[UIFontfontWithName:@"Helvetica"size:20]lineBreakMode:UILineBreakModeWordWrapalignment:UITextAlignmentCenter];
- }
- }
UIScrollView是iphone中的一个重要的视图,它提供了一个方法,让你在一个界面中看到所有的内容,从而不必担心因为屏幕的大小有限,必须翻到下一页进行阅览。确实对于用户来说是一个很好的体验。但是又是如何把所有的内容都加入到scrollview,是简单的addsubView。假如是这样,岂不是scrollView界面上要放置很多的图形,图片。移动设备的显示设备肯定不如PC,怎么可能放得下如此多的视图。所以在使用scrollView中一定要考虑这个问题,当某些视图滚动出可见范围的时候,应该怎么处理,是不管它那,还是进行内存回收或者重利用。苹果公司的UITableView就很好的展示了在UIScrollView中如何重用可视的空间,减少内存的开销。
首先还是看官方API如何解释UIScrollView,一下是翻译官方UIScrollView的帮助文档。
UIScrollView类支持显示比屏幕更大的应用窗口的内容。它通过挥动手势,能够使用户滚动内容,并且通过捏合手势缩放部分内容。
UIScrollView是UITableView和UITextView的超类。
UIScrollView的核心理念是,它是一个可以在内容视图之上,调整自己原点位置的视图。它根据自身框架的大小,剪切视图中的内容,通常框架是和应用程序窗口一样大。一个滚动的视图可以根据手指的移动,调整原点的位置。展示内容的视图,根据滚动视图的原点位置,开始绘制视图的内容,这个原点位置就是滚动视图的偏移量。ScrollView本身不能绘制,除非显示水平和竖直的指示器。滚动视图必须知道内容视图的大小,以便于知道什么时候停止;一般而言,当滚动出内容的边界时,它就返回了。
某些对象是用来管理内容显示如何绘制的,这些对象应该是管理如何平铺显示内容的子视图,以便于没有子视图可以超过屏幕的尺寸。就是当用户滚动时,这些对象应该恰当的增加或者移除子视图。
因为滚动视图没有滚动条,它必须知道一个触摸信号是打算滚动还是打算跟踪里面的子视图。为了达到这个目的,它临时中断了一个touch-down的事件,通过建立一个定时器,在定时器开始行动之前,看是否触摸的手指做了任何的移动。假如定时器行动时,没有任何的大的位置改变,滚动视图就发送一个跟踪事件给触摸的子视图。如果在定时器消失前,用户拖动他们的手指足够的远,滚动视图取消子视图的任何跟踪事件,滚动它自己。子类可以重载touchesShouldBegin:withEvent:inContentView:,pagingEnabled,和touchesShouldCancelInContentView:方法,从而影响滚动视图的滚动手势。
一个滚动视图也可以控制一个视图的缩放和平铺。当用户做捏合手势时,滚动视图调整偏移量和视图的比例。当手势结束的时候,管理视图内容显示的对象,就应该恰当的升级子视图的显示。当手势在处理的过程中,滚动视图不能够给子视图,发送任何跟踪的调用。
UIScrollView类有一个delegate,需要适配的协议是UIScrollViewDelegate。为了缩放和平铺工作,代理必须实现viewForZoomingInScrollView:和scrollViewDidEndZooming:withView:atScale:方法。另外,最大和最小缩放比例应该是不同的。
重要的提示:在UIScrollView对象中,你不应该嵌入任何UIWebView和UITableView。假如这样做,会出现一些异常情况,因为2个对象的触摸事件可能被混合,从而错误的处理。
这些都是官方API的解释,重点是理解UIScrollView怎么来控制手势的。可以由canCancelContentTouches这个方法的运用来解释UIScrollView如何控制手势的。
假如你设置canCancelContentTouches为YES,那么当你在UIScrollView上面放置任何子视图的时候,当你在子视图上移动手指的时候,UIScrollView会给子视图发送touchCancel的消息。而如果该属性设置为NO,ScrollView本身不处理这个消息,全部交给子视图处理。
那么这里就有疑问了,既然该属性设置未来NO了,那么岂不是UIScrollView不能处理任何事件了,那么为何在子视图上快速滚动的时候,UIScrollView还能移动那。这个一定要区分前面所说的UIScrollView中断touch-Down事件,开启一个定时器。我们设置的这个cancancelContentTouches属性为NO时,只是让UIScrollView不能发送cancel事件给子视图。而前面所说的时,中断touch-down事件,和取消touch事件是俩码事,所以当快速在子视图上移动的时候,当然可以滚动。但是如果你慢速的移动的话,就可以区分这个属性了,假如设定为YES,在子视图上慢速移动也可以滚动视图,但是如果为NO。因为UIScrollView,发送了cancel事件给子视图处理了,自己当然滚动不了了。
事件处理看过了,就要考虑scrollView如何重用内存的,下面写了一个例子模仿UITableView的重用的思想,这里只是模仿,至于苹果公司怎么实现这种重用的,他们应该有更好的方法。
这里的例子是在scrollView上放置4个2排2列的视图,但是内存中只占用6个视图的内存空间。当scrollView滚动的时候,通过不停的重用之前视图的内存空间,从而达到节省内存的效果。重用的方法如下:
1.如果scrollView向下面滚动,一旦一排视图滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,也就是改变位置到达末尾,达到重用的效果。
2.如果scrollView向上面滚动,一旦最末排的视图view滚出了可视范围,就改变滚动出去的那个view在scrollView中的frame,移动到最前面。
下面就需要在你创建的视图控制器中,创建一个重用的视图数组,用来把这些要显示的视图放入内存中,这里虽然界面上显示的是2排2列的四个视图,但是当拖动的时候,可能出现前面一排的视图显示一部分,末尾一排的视图显示一部分的情况,所以重用的数组中要放置6个视图。下面是定义的一些宏:
- #definesMyViewTotal6
- #definesMyViewWidth150
- #definesMyViewHeight220
- #definesMyViewGap10
具体实现代码如下:
- _aryViews=[[NSMutableArrayalloc]init];
- for(inti=0;i<sMyViewTotal;i++){
- CGFloatx;
- if(i%2){
- x=sMyViewWidth+sMyViewGap+sMyViewGap/2;
- }
- else{
- x=sMyViewGap/2;
- }
- CGFloaty=(sMyViewHeight+sMyViewGap)*(i/2);
- MyView*myView=[[MyViewalloc]initWithFrame:CGRectMake(x,y,sMyViewWidth,sMyViewHeight)];
- myView.showNumber=i;
- [myScrollViewaddSubview:myView];
- [_aryViewsaddObject:myView];
- [myViewrelease];
- }
所以这里的核心方法是,首先要判断是向上滚动还是向下滚动方法如下:
- -(void)scrollViewDidScroll:(UIScrollView*)scrollView{
- BOOLdirectDown;
- if(previousOffSet.y<scrollView.contentOffset.y){
- directDown=YES;
- }
- else{
- directDown=NO;
- }
- previousOffSet.y=scrollView.contentOffset.y;
- //防止最开始就向上面拖动的时候,改变数组视图树的位置。
- if(scrollView.contentOffset.y<0){
- return;
- }
- if(directDown){
- NSLog(@"down");
- MyView*subView=[_aryViewsobjectAtIndex:firstViewIndex];
- CGFloatfirstViewYOffset=subView.frame.origin.y+subView.frame.size.height+sMyViewGap;
- //寻找第一个视图是否滚动出去
- if(firstViewYOffset<scrollView.contentOffset.y){
- //改变数组中第一排可见视图的位置。
- [selfmoveIndexInViewsWithDirect:YES];
- }
- }
- else{
- NSLog(@"up");
- MyView*subView=[_aryViewsobjectAtIndex:(firstViewIndex+sMyViewTotal-2)%sMyViewTotal];
- CGFloatlastViewYOffset=subView.frame.origin.y-scrollView.bounds.size.height;
- if(lastViewYOffset>scrollView.contentOffset.y){
- [selfmoveIndexInViewsWithDirect:NO];
- }
- }
- }
每次滚动的时候先判断滚动位置即offset,和先前的比较。如果先前的大就是向下滚动,否则就是向上滚动。
找到了向下滚动了,就该判断是否子视图已经离开了可视范围。方法就是判断当前offset和视图的位置进行比较。如果判断滚到离开了可视范围,然后就是要改变重用视图数组中第一个视图的位置了。这里用了firstViewIndex来记录scrollView中第一个可见视图的位置,循环使用这6个视图达到重用的目的。自然firstViewIndex上面的一个视图就是最后一个视图的位置(firstViewIndex+sMyViewTotal-1)%sMyViewTotal。所以这里需要改变重用视图中firstViewIndex即第一个可见视图的位置。代码如下:
- -(void)moveIndexInViewsWithDirect:(BOOL)forward{
- [UIViewsetAnimationsEnabled:NO];
- if(forward){
- for(inti=firstViewIndex;i<(firstViewIndex+2);i++){
- MyView*subView=[_aryViewsobjectAtIndex:i%sMyViewTotal];
- subView.showNumber=subView.showNumber+sMyViewTotal;
- subView.frame=CGRectMake(subView.frame.origin.x,subView.frame.origin.y+(sMyViewTotal/2)*(sMyViewHeight+sMyViewGap),subView.frame.size.width,subView.frame.size.height);
- }
- firstViewIndex=(firstViewIndex+2)%sMyViewTotal;
- }
- else{
- intlastViewIndex=firstViewIndex+sMyViewTotal-1;
- for(inti=lastViewIndex;i>(lastViewIndex-2);i--){MyView*subView=[_aryViewsobjectAtIndex:(firstViewIndex+sMyViewTotal-i)%sMyViewTotal];
- subView.showNumber=subView.showNumber-sMyViewTotal;
- subView.frame=CGRectMake(subView.frame.origin.x,subView.frame.origin.y-(sMyViewTotal/2)*(sMyViewHeight+sMyViewGap),subView.frame.size.width,subView.frame.size.height);
- }
- firstViewIndex=(firstViewIndex+sMyViewTotal-2)%sMyViewTotal;
- }
- [UIViewsetAnimationsEnabled:YES];
- }
这里创建的子视图数字属性,是用来在视图上画数字的,这样就可以看到视图重用的效果了,应该是从0开始到无穷多,但是实际上内存中就创建了6个视图。
- -(void)drawRect:(CGRect)rect
- {
- //Drawingcode
- NSString*text=[NSStringstringWithFormat:@"%d",showNumber];
- [[UIColorredColor]set];
- [textdrawInRect:CGRectMake(rect.origin.x,rect.origin.y+rect.size.height/2-30,rect.size.width,30)withFont:[UIFontfontWithName:@"Helvetica"size:20]lineBreakMode:UILineBreakModeWordWrapalignment:UITextAlignmentCenter];
- }
- }
相关推荐
UIScrollView 用法详解UIScrollView 用法详解
UIScrollView、UIScrollView基本用法、UIScrollView详解,UIScrollView常用方法
在iOS开发中会用到的UISCrollView与UITableView嵌套使用的方法
UIScrollView与UIPageControl的简单应用以及一些非常基本的使用方法
UIScrollView-中心该项目说明了使用contentInset在UISCrollView contentInset内容UISCrollView方法。 可以在上找到有关该项目的葡萄牙语 。
主要介绍了iOS应用开发中UIScrollView滚动视图的基本用法总结,作者还介绍了重写UIScrollView中的hitTest方法来解决长按的事件问题,需要的朋友可以参考下
使用方法: viewWillAppear中实现 showbigImage=[[ShowBigImageBox alloc]init]; [showbigImage setShowBigImageBoxDelegate:self]; viewWillDisappear中实现:[showbigImage clearBigImageBox];//在页面结束的...
UIScrollView使用非常广,本文研究UIScrollView各属性和方法,明白它们的意义、作用。这里我们整理UIScrollView一些常见用法以及一些效果的实现思路。
DVOBouncer, 将重力弹跳添加到UIScrollView内容 #DVOBouncer将重力弹跳添加到UIScrollView内容。用于交互式教程的用途,说明你希望向用户显示滚动视图另一端的更多内容。DVOBouncer使用UIKit动力学来模拟滚动视图...
主要介绍了iOS开发中使用UIScrollView实现无限循环的图片浏览器的方法,感兴趣的小伙伴们可以参考一下
DMScrollViewStack ... 您可以使用公开的方法来添加或删除子视图。 子视图可以是直接的 UIView 或 UIScrollView 子类。 -setViews: // set a subview list (no animation) -addSubview:animated:completi
MXParallaxHeader ...用法 如果您想尝试一下,只需运行: pod try MXParallaxHeader 向UIScrollView添加视差标头很简单,例如: Swift let headerView = UIImageView () headerView. image = UIImage ( named
易于使用:只需一行代码即可使UIScrollView支持“拉动刷新”或“无限滚动” 屏幕 要求 iOS 8.0以上 迅捷3.0+ 安装 卡塔加 将以下代码添加到Cartfile并运行Carthage update 。 github "DanisFabric/Infinity" 手动...
一、好多App都有上下滑动UIScrollview隐藏或者显示导航栏,在这里我说说我觉得有用的几种方法: 1.iOS8之后系统有一个属性hidesBarsOnSwipe Objective-C代码如下 self.navigationController.hidesBarsOnSwipe = YES; ...
最重要的是一个更新 UIImageView 尺寸和位置,以及更新 UIScrollView contentSize 的方法。 但是如果在 AutoLayout 下,由于没有绝对的位置了,所有的位置要使用约束来限制,所以变成了更新约束位置。当图片放
主要介绍了iOS开发中使用UIScrollView控件来实现图片缩放的方法,代码基于传统的Objective-C,需要的朋友可以参考下
主要介绍了iOS开发中使用UIScrollView实现图片轮播和点击加载的方法,代码基于传统的Objective-C,需要的朋友可以参考下
紧随UIScrollView的轻量级可滚动UINavigationBar。 该项目的灵感来自于Chrome,Facebook和Instagram iOS应用中的导航栏功能。 安装 可可豆 将pod GTScrollNavigationBar添加到您的Podfile。 手动地 将...
RGMPagingScrollView是一个简单的UIScrollView子类,它管理可重复使用视图的单个水平或垂直行的呈现,类似于iOS上的“照片”应用程序。 该API遵循UITableView和UICollectionView设置的模式,这使它易于理解和使用。...