致力打造最好用的APP首页组件 - YRichView

背景:

公司很多首页,各种列表分类页、以及商详页,都采用了如下的形式:

但是公司的并没有一个好的组件可以使用,不仅每次重复复制代码,而且体验也很差,因为采用很多手势的原因,造成各种手势冲突,划一下就停顿(不是因为卡)。于是就有了做组件的想法。

分析

一、 相似性

特性图

  • 上面都有一块类似header的部分
  • 中间有一块分类表,总是存在于屏幕上,类似于tableview的section header。
  • 下面是各个分类的内容,有可能是UITableView,有可能是UICollectionView,还有UIScrollView。
二、 分析其它APP

看了淘宝、京东、天猫、蘑菇街等一系列APP之后,发现他们的首页上,有的header部分,在置顶view的上面,有的在下面。而蘑菇街正是和我公司采用最接近。

既然有最相近的APP了,第一步当然是参考人家是怎么实现的。没源代码?reveal和flexbox可不是吃素的,越狱机是他们的归宿。其实最不容易理解的就是,他的视图层级了。最难的无非就是header部分和section header部分是如何处理的。
既然有神器在手,总不能浪费,经过一番研究后得出结论是:

  • 一个大的只能横向滚动的scrollView里面放了N个类目的tableView。上面的header和section header是通过contentoffset来变化的。
  • 第一个tableview上面是等高的tableHeaderView。

使用的方便性

既然是号称最好用的App组件,那么好用是必须的,应当合理的传入各自定制的视图,合理地懒加载等等。这里的通信方式我采用代理,与UITableview的代理相近。懒加载就是,假设有十个scrollview,但目前只显示一个,我就只加载第一个,等划到第二个,才开始读取。省内存。未来会控制在屏幕上scrollview的总数量。

实战中遇到的问题

照着上面的结论做呗,可惜坑有很多:

一、 做为一个优秀的组件,如何拿到子tableview的contentOffset?

解决方案:swizz总觉得太黑魔法了。于是想到利用kvo来实现。

二、 在第一个tableview滚动到底的时候,然后右移,将第二个tableview向上滚一点,这时候向左划应该是原有的ContentOffset还是将它置成0?

解决方案:如果是使用原有的contentOffset,就会出现,你不知道向上划动到底是划下面的tableview呢,还是整体。但如果是置0,就会遗失用户的浏览记录。二者不能共存,后来采用置0方案。

三、 如果下面采用collectionView怎么解?

解决方案:tableview的话,正好可以采用tableheader。但collectionView没有!。为了更好的处理,我改成了用Inset来代替tableheader的方法。这样只要是传入的是UIScrollview都行。

四、 刷新控件怎么解?

解决方案:经过很久的思量,刷新控件肯定是写在各个scrollview上的。但采用inset来实现,普通的刷新控件会将inset重置掉,或者直接加在contentOffset为0的位置上,也就是吸顶视图的后面。我翻阅了多个刷新控件,找出最具代表的三类,将他们最后更新时间的start数写在后面:
EGOTableViewPullRefresh (3,262) (最后更新于2014年3月之前)
SVPullToRefresh (4,112) (最后更新于2013年3月之前)
MJRefresh (6,809) (最后更新于2016年1月份)
我试了这三款,其中EGO会对inset进行重置。PullToRefresh也不支持inset不为0的情况,只有星级最多的MJRefresh支持。终于我在只支持tableview和支持scrollview的方案上,我选择了scrollview + mjrefresh。(既然是打造最好的App组件,咱就不将就)

五、顶部这一块视图,如果是贴在最上层,会覆盖滚动条。

解决方案:是的,解决方案就是把他贴在scrollview上面,这样scrollview在滚动时,产生的滚动条会自动显示在最上方。但是这里又有一个问题,如果是贴在子scrollview上,那么在移动时就移动不了了。这个问题是后来有位同事告诉我的,将tableview的clipsToBounds关上,默认为开,这样就畅通无阻了。

六、何时去获取delegate的问题。

解决方案:因为不想受限于用户在init完后设置代理的问题,所以暂时代码会在layoutSubviews里写。后续会考虑设置代理的时候进行。

地址库

看了这么多文字还不如看个代码容易?好,附上github地址:https://github.com/LiZunYuan/YRichView/tree/master