iOS 无限滚动屏、走马灯、弹幕效果实现

前言:我是一个很懒的人,所以除了写小说,几乎不写别的什么文章,最近赶上公司做些社区化的需求,有需要写一个滚动留言板,有些像弹幕,所以自己就封装了一个,觉得可能对大家有用,所以就发上来,大家有用到的,可以参考参考。

一、效果

一行无限滚动
两行无限滚动
多行无限滚动

二、方案和策略

1. 我们暂时定义每一个横向滑动的组件叫轨道,每一个轨道上有若干个text控件,任一控件都是从屏幕最后侧外开始进入屏幕并开始滚动,所以每个text控件的中心点从初始值运动到恰好滑出最左侧屏幕的时候,其中心点的位移就是整个屏幕的宽,如下图所示:

控件center.x位移是屏幕宽

2. 每一个控件从右侧屏幕外开始运动,其运动距离(movedLength)刚好等于自身宽度(width)的时候,说明控件刚好运动到其尾部与屏幕右边框对齐(有控件间距的时候,则是其运动距离刚好等于其自身宽度加控件距离),如下图所示:

alabel.movedLength = alabel.frame.size.width + self.controlSpace

3. 在1的场景下,某一个控件刚好移出屏幕,则发出通知,将当前控件从屏幕移除,然后发回上层业务缓存起来。

4.在2的场景下,某一个控件刚好完全进入屏幕,此时需要发通知,通知上层业务方加载进入下一个控件,此时如果业务方控件缓存池有多余控件,则优先从缓存池复用控件,如果没有,则创建一个新的控件。(此处类似UITableViewCell复用)

5. 由以上可知,每一个控件必须有两个属性,一是初始加载到屏幕上的centerX值,二是记录本控件位移量的movedLength值。

6. 轨道组件维护着一个时钟,可以是NSTimer,也可以是DisplyLink,这个时钟每次刷新,都将遍历当前轨道中所有text控件,修改其x值和movedLength值,然后判断其x值是否满足刚好滑出屏幕和刚好完全滑入屏幕的条件,符合的话,采取对应的3或者4的操作

7. 作为轨道的数据源,上层业务方会提供一个数据队列dataArray,你还要维护一个游标作为索引,index,每次内层轨道索要一次数据,你就返回一个数据,然后将index++,

   7.1 如果你的app需求不需要无限循环,则在获取下一条数据的时候判断,是否达到了外层dataArray的尾部,如果达到了则不再返回数据,你的轨道发现拿到了空数据,则暂停滚动。

   7.2 如果你的app需要无限循环滚动,则在获取下一条数据的时候判断,是否达到了外层dataArray的尾部,达到了尾部,则将index重新归零,指向头部。

8. 特殊情况:有这样一种情况,比如dataArray数据过少,比如只有一条两条短的,一屏就能展示完,你还需要判断,当需要拉取下一条数据时,如果下一条数据与当前轨道中其它数据一样,则不拉取;然后你需要在轨道中额外添加一条判断:当text控件尾部抵达屏幕左侧边框时,判断如果后面没有别的控件,则从缓存池继续循环拉取。(判断的方法很简单,当前轨道中的控件就像UITableView的visibleCells,当前控件是最后一个控件的话,就表面后面没有别的控件)


三、上代码

1. 如果你们需求很简单,只需要一个text控件,就可以只定制一个我们自己的text控件,这个控件多了两个属性,如下:

2. 如果你的需求复杂,需要定制单独的文本View,如本文开头所示,可以定制一个自己的baseView,如下:

其数据类如下:

3. 务必注意:为了避免意外卡顿,需要将每一个text控件的frame和数据都准备好,放在数据类中,这样你的轨道控件可以只做渲染和时钟操作,避免大量计算造成卡顿或者遗漏数据

4. 核心控件,单轨道

5. 单轨道BDSKAutoRunView的.m文件如下:

    5.1 首先添加一个分类,将时钟以及放置滚动内容视图生命一下,还有一个线程访问的简单锁

  5.2 然后初始化一些必要数据,这里文本控件的横向间距默认为20,滚动速度1,

5.3 添加将外层传入的view加载到当前轨道的方法,默认将之放在轨道末尾,再给它加上底层txt控件点击事件的传递,最后开启时钟

 5.4 时钟与时钟方法概览,其中start,pause,stop是供外部调用,beginTimer与stopTimer等供内部调用

 5.5 具体的timer方法

5.6 核心方法,时钟刷新动作


   5.7 最后是点击动作和获取下一条通知

    5.8 到此处为止,单轨道定制完成,开始定制多轨道

6. 滚动屏控件头文件

7. 滚动屏BDSKSSRollView.m文件,添加一个锁

8. 定制初始化方法和rollPathCount的setter方法,创建相应数量的轨道

8.1 实现轨道的delegate,为止提供数据和获取事件通知,这里缓存对象,简单使用对象的内存地址作为key,你也可以用其他哈希值

8.2 外部数据池游标需要加判断,不能越界,将要越界时,返回头部,继续返回数据

8.3 复用返回数据核心函数,每次先取缓存的text控件,有则利用新数据刷新控件,没有缓存text控件,则创建新的,最后的startCenter与位移信息重新设置。

9.综合以上,就是滚动屏所有相关代码,使用的时候怎么使用呢?

初始化一个滚动屏的view,然后添加到你想要添加的视图上就可以了,其中titleArray就是你从服务端获取到的数据源。这里有个要注意的策略:什么时候去再次拉取服务端数据。

有两种方案,1.第一次拉取到数据后,先让屏幕滚动着,然后在后台静默继续请求数据,然后塞进titleArray中就可以了 2. 第一次拉取到数据后,让滚动屏先滚动,然后在游标index++到倒数第N个时,发通知,由外部发请求从服务端拉取新数据

10. 由于复用机制的存在,使得屏幕上的控件始终不会累积增加,所以内存消耗并不大,而如果不服用,直接从屏幕上remove然后由系统抛弃,每次都重新创建新的text控件也没问题,只是每次都要创建一个新的控件,简单控件还好,复杂控件就损耗性能了。


总结:以上就是全部的滚动屏和走马灯定制的全部内容,只是自己花两天简单做的实现,找时间我会把demo放出来,有需要的朋友可以下载,当然,如果有什么疑问,欢迎留言和咨询,不过我比较懒,不一定每天登陆上来,所以不一定能及时回复,还请海涵。

你可能感兴趣的:(iOS 无限滚动屏、走马灯、弹幕效果实现)