很多 APP 首页的广告都有图片循环滚动功能, 我做的项目中正好也需要这个功能
我说主要思路, 并提供我写的代码例子
广告要滚动, 首先想想具有滚动功能的原生控件有哪些, scrollView, tableView, collectionVIew, webView......
广告要水平滚动, 所以只剩 scrollView, collectionVIew 可以试试
方法一: scrollView
假设有5张图片, 分别叫 A,B,C,D,E, 每张图片放到 imageView 上, 然后 imageView 放到 scrollView 上
用户有两种操作, 向左滚, 向右滚
当向左滚, 滚到第1张时, 就是最左边那张时, 我把第5张图片给挪过来(设置 frame 值), 如下图
[A],B,C,D,E, // 现在显示 A 图片, 我设置5张图片的 frame 值使得图片顺序变成这样
E,[A],B,C,D // E 被挪到 A 的前面了, 实现了循环滚动, [ ]括号表示正在显示的图片
向右滚也同理,
A,B,C,D,[E], // 现在显示 E 图片, 在 E 显示完之后
B,C,D,[E],A // 马上把 A 挪到 E 的右边
具体在哪里挪, 请看一下 scrollView 的所有代理方法, 想想在哪个方法里比较合适
可以优化的地方, 假设图片有很多张, 没必要创建那么多 imageView, 只要3个 imageView 就够了, 想想2个够吗?
3个 imageView, 分别叫 A,B,C, 我只显示中间那个 imageView, 用 [ ] 括住的那个
A,[B],C
C,[A],B// 向左滚, 把 C 移到了 A 的左边
B,[C],A // 再向左滚, B 移到 C 的左边
可是 N 张图片怎么放到 3 个imageView 里? 还记得<数据结构>里的循环队列吗?
我每次去循环队列里取一张图片X作为当前显示的图, 结构如下
X前一张 ,[图片X], X后一张
C语言中数组和链表都可以实现循环队列, 想想 OC 中用什么实现循环队列?
我用 NSArray + NSInteger 索引实现, 所有图片放进 NSArray *array 里, 再来个 NSInteger index; 循环的索引
加1操作: index = (index + 1) % array.count;
减1操作: index = (index - 1 + array.count) % array.count;
加1操作取前一张, 减1取后一张
scrollView 的方法就到这里了
方法二: collectionView
由于方法一自己写的 imageView 重用太过复杂, 而且scrollView 代理方法有局限性(我想在手指离开屏幕时, 获得最终结果是左滚还是右滚,scrollView 没有这个代理方法), 导致连续滚动时会出现不连贯的问题
collectionView 自带了 cell 重用, 还可以设置为水平滚动, 所以我想到在 cell 上放 imageView, 借用collectionView的重用机制, 那怎么实现循环功能呢?
还是有5张图片, 分别是 ABCDE, 放在数组里, A 在 0 位置, B 在 1 位置,,,,如此类推
我把这组图片复制100份, 存进数组里, 那么数组里面的东西就像这样
ABCDEABCDEABCDE....// 看出规律没, ABCDE 循环放, 这个数组就有 100*5 个元素
然后我把 collectionView 定位到中间的第 50 组的, 第0张图片来显示, 如下图, 前面还有49组, 后面还有50组图片
......ABCDE,[A]BCDE,ABCDE......
这样就实现了循环滚动了吧, 但是有问题
问题1. 图片很多, 很耗内存
问题2. 用户一直往前滚动, 迟早会滚到边界
问题1解决方法
还记得<数据结构>里的地址排序吗, 不记得我来说说
假如数组里的元素很大(1MB 以上), 移动很不方便的时候, 要对他排序, 那么我可以对他的地址进行排序, 而不移动元素内容, 我来一张表, (地址, 元素的地址), 保存排序结果即可, 排序不是重点不展开了
所以那 5 图片我没必要复制 100 份了, 我把5张图片的地址, 复制100份, 存在数组里, 数组地址是 long int 型的吧
假设 long int 占 8个字节, 那么这个数组大小是 100*5*8 = 4000 个字节, 差不多 4KB 而已, 项目中一张图片是 200多k
那么我就用, 下面的数组表示图片了, 拿到数组内容, 再去图片数组里拿具体图片即可, 解决内存占用问题
......012340123401234......
问题2解决方法
用户一直往前滚动, 迟早会滚到边界, 这个很好解决, 当 collectionView 停止滚动时, (想想停止滚动是哪个代理方法), 我去把 collectionView 重新定位到第50组的图片那里去, 并且不用动画的滚动, 即可
除非有人手指不离开屏幕, 一直朝一个方向滚 collectionView, 导致 collectionView 动画停止不了, 无法重定位到中间
那么可以把100份的数组, 开到1000份, 那么就有 5000个图片地址了, 他手指不松开的滚动, 还是会到边界, 遇到这么无聊的人, 我也是给他跪了....
代码下载地址:
collectionView循环滚动 http://pan.baidu.com/s/1skeLQLf
scrollView循环滚动 http://pan.baidu.com/s/1KrIuM