iOS UITableView中选定区域曝光的策略研究

1,776 阅读3分钟

列表页中,cell在可见区域曝光之后执行某些业务或者数据统计,是一个产品和数据产品及其基础的需求。不过这方面成熟的解决方案不太多。 最近有需求。做一个如下图类似的场景。当cell展示在红框区域内之后 再去执行某些逻辑。如接口上报,倒计时等等。

解决方案比较简单,重点是背后的原理。希望展示出来和大家共同进步。

问题1 什么时机去统计页面内可见cell 解决方案1 比较容易想到的可用的方案(初始值)tableView被add到subview上和 tableView的回调方法scrollViewDidScroll(变化) scrollViewDidScroll这个回调可以反映了任何一次tableview中偏移量的变化。 原因是:UITableview继承自UIScrollView。展示原理也是UIScrollView的content偏移+cell复用。 UIScrollView偏移本质是scrollView中Pan手势,改变UIScrollView的bounds 从而导致contentView的坐标变化。逻辑如下![] 同时发送回调。scrollViewDidScroll。 如果在这个时机。毫无疑问可以得到所有的变化状态。但是在这个时机去做,会存在频率过高的问题。因为这是个source0事件。处理频率会等于runloop的循环频率。

如果一个runloop循环事件等于16.6ms(60fps)页面是流畅的。如果超过83ms(12fps) 就会有明显卡顿的感受了。 所以在这个时机进行页面视图统计和数据上报处理,是有效,但是负担过重的。 解决方案2 第二个方案是定时器方案。这个页面本身就有一个定时器用来做页面的倒计时销毁逻辑。利用这个定时器能大大降低页面业务的负载。

问题2 如何去做,做的过程中又会碰到哪些问题。 当定时器到时间刷新页面数据源,刷新页面UI。 假设方案采取计数是是数据源一部分,由定时器去刷新数据源+1,然后刷新TableView。当我们刷新完数据源(假设消息数目有变化) 然后reloaddata之后。整个页面有正确的展示么? 答案是不会。因为tableView 的reload方法是一个异步的方法。(不是子线程)。进行reload之后,

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

方法。此后等待RunTime Beforewaiting和exit的时机 即Tableview layoutSubview的时机,才会去执行 cellforrow heightforrow的方法。进行页面刷新。 所以在reloaddata之后,是不可行的。 最终我选择的时机是Cell的layoutSubview。 可能会有担心。 担心1 layoutsubview是否和runloop的exit时机一样。 事实上。及时快速滑动,页面cell必须有frame变化或者页面调用layoutifneeded 。在beforewaiting时机 才会触发layoutsubview. 上下短距离滑动,很容易可以看到tableview一直在layoutsubview 但是只要没有触及打的tableviewcell的变化,cell也也不会触发layoutsubview.及时触发,频率我们也可以接受。

通过cell ,计算出在整体页面vc.view的位置 判断是否在期望位置上。然后执行逻辑

 [tableview convertRect:self.frame toView:view];

担心2 是否快速滑动 导致无法正确统计 可以计算快速滑动pan手势的速度(velocity)。如果速度小于 可视区域高度/1s。 则该上述的方案是有效地。

优化1 将tableviewcell和model进行关联。已经上报的cell将model进行标识,不予处理。防止重复上报。消耗资源。

参考资料 : blog.ibireme.com/2015/05/18/…