无限滚动视图
2011-12-08 23:10 v2m 阅读(2548) 评论(2) 编辑 收藏 举报一个可以无限滚动的程序,基本功能是实现了,但是还有很多地方需要完善.先记录一下.下面是代码的相关:
1.基本思路是对UIScrollView重载,content的首尾各增加一个多余的视图使得看起来很连续.又,每次scroll的时候都会调用layoutView,所以可以在一定的offset之后重置之而不影响视觉效果.而且把contentview的中心与frame的中心重叠,这样就两端滚动都非常顺畅,用scrollDistance记录最开始需要的偏移(中心重叠的偏移).
// 纵向滚动 -( void )verticalScroll { CGPoint currentOffset = [ self contentOffset]; CGFloat distanceY = 0; if ((currentOffset.y-scrollDistance) > viewHeight || (currentOffset.y-scrollDistance) < -viewHeight) { .... } } // 滚动就相应调整 -( void )layoutSubviews { // 首次出现或者重载数据时,初始化subviews if (layoutFirst) { [ self firstlayoutToShow]; layoutFirst = !layoutFirst; } [ super layoutSubviews]; if (!tooShortContent) // 需要无限滚动,相应改变 [ self verticalScroll]; } |
2.如果大量的subviews呢?这就引导我进行了视图复用(当然,我的代码里面的复用还需要很大改进).只生成充满frame+头尾多余两个的subview,如果超过了一定的offset就把subview移除superview,加入一个重用池(一个字典结构);等需要特定subview的时候先去池中找,没有就重新生成一个。这让内存占用最小化。
图:1.初始两端各多出一个subview,contentview与frame中心重叠.2.滚动一定范围后对subview重新处理(程序中用了另一个数组记录,便与首元素处理).3.contentview重新布局,offset重置.
3.一般的无限滚动其实都用在picker中,这就需要一种选择,所以可以在滚动结束后判断需要设置哪个subview是被选择的,再调整一下offset。所以最好是让自己做自己的UIScrollViewDelegate。
-( void ) visibleRect { CGPoint currentOffset = [ self contentOffset]; CGPoint centerPoint = CGPointMake(0, 0); for (ISView* view in viewArray) { // 找到合适的选择项 CGRect r = view.frame; centerPoint = CGPointMake(viewWidth/2, r.origin.y -currentOffset.y + viewHeight/2); if ([ self pointShouldFitRect:centerPoint withRect:pickRect]) { CGFloat diffY = centerPoint.y - (pickRect.origin.y+pickRect.size.height/2); currentOffset.y += diffY; [ self setContentOffset:currentOffset animated: YES ]; [ self changeto:[viewArray indexOfObject:view]]; return ; } } // 下面是subviews不能充满整个frame情况下需要选择第一个或最后一个 if (centerPoint.y > pickRect.origin.y) { [ self selectIndex:0]; } else { CGFloat diffY = centerPoint.y - (pickRect.origin.y+pickRect.size.height/2); currentOffset.y += diffY; [ self setContentOffset:currentOffset animated: YES ]; [ self changeto:[viewArray count]-1]; } } |
4.既然可以选择,那就需要读写,所以添加了一个选项改变的代理方法来跟踪值的改变。设置选择框范围的同时可以设置默认的选择项(因为如果没有选择范围的话,选项没有意义).
整个代理方法如下:
@protocol ISScrollViewDelegate -( NSInteger ) numberOfSubViews:(ISScrollView*)s; // 子视图个数 -(ISView*) viewForScroll:(ISScrollView*)s AtIndex:( NSInteger )index; // 申请子视图 @optional -( void ) scrollView:(ISScrollView*)s ChangeSelectedFrom:( NSIndexPath *)oldSel to:( NSIndexPath *)sel; // 选项改变 @end |
5.如果内容改变呢?所以又写了一个reloadData方法来重新载入相关数据。
6.写着写着发现其实这就是UITableView的实现方法,如果想要更高端的定制一下UITableView,稍微改动下就可以了。比如可以很简单实现这样的视图:
7.横竖两个方向都可以支持,我又不喜欢if来去的,就分到两个类中了。但是这样的方法应该是不好的,因为我改了其中一个类,必定要改另一个,而改的位置代码,都基本相同,只不过x变成了y,width变成了height,或许有更好的解决方法。
8.主要的文件结构
9.整个代码在这里,里面有三个例子,水平锤直选择的小例子,图片浏览(这个不怎么顺畅,待调整),一个日期选择(用到重载数据与回调).
10.使用的时候主要要主要 设置代理isdelegate,设置subview大小,设置contentsize(不能太小,最好比frame+2*subview 大)。要设置选择区域的话CGrectZero默认会设在中间位置。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂