美文网首页自己尝试等装一下iOS开发好文学学人家的框架
SwipeTableView —— 一款好用的,既能上下滚动又能

SwipeTableView —— 一款好用的,既能上下滚动又能

作者: roylee_stillway | 来源:发表于2016-07-16 00:50 被阅读3450次

这是一个类似半糖首页、QQ音乐列表、美丽说首页、格瓦斯电影详情页,既能上下滑动,同时用能左右滑动的控件。项目地址GitHub

说起这个项目,还是得谈一下一开始写这个项目的缘由。前一阵子,公司项目首页改版,要求作出半糖首页的效果。看了一眼半糖之后,心中一万只草泥马奔过,怎么会做这种设计?后来,想了一天的时间,终于把大概的实现原理捋顺出来,又花了几天的时间来一步步的实现,解决bug。最后终于可以实现上下与左后滑动同时兼容的效果了。由于只是首页改版,所以只是首页实现了效果,也并没有单独写一个控件,可是,一周之后,悲剧的事发生了:新的产品设计中有几个页面都是这样的设计。好吧,还是乖乖的写个控件吧。于是,就有了SwipeTableView。

先来几张预览吧:

再来说一下实现原理:

最初的设计并没有考虑兼容第三方下拉刷新的问题,所以最初的设计更简洁,扩展性也更好。下面是原理的结构图—— 

1. 首先,为了实现左右滑动的功能,需要一个view来作为所有单一item的父视图载体,并提供左右滑动的功能,这里没有比`UICollectionView`再合适的了。所有,我用一个CollectionView作为contentView。

2. 有了CollectionView作为载体之后,就可以把每一个ScrollView作为CollectionView的item平铺了。之后,最关键的问题,也是最难处理的问题,就是在滑动CollectionView的时候,怎样保证前后item能够对齐呢(因为悬停,只有对齐才行)?最后想到的解决办法,就是在cellForItem的方法中,对前后两个item的contentOffset进行adjust一致性调整。这样能实现前后两个item的位置是合理的。

3. 最后一个主要的问题就是,多个item共用一个header与bar的问题。既然共用,最后想到,那就让header与bar与CollectionView一样作为SwipeTableView的子视图,并别在图层最上面。由于是独立的view,之后就要解决当前item滑动同时滚动对header与bar做跟随处理的问题了。在这里,对当前的item进行KVO,在item的contentOffset发生变化的时候,同样改变header与bar的位置,使之总是跟随scrollview的滚动,并在悬停的位置做判断,固定bar的frame的y值。

4. 这样,基本的实现就完成了。同时,`SwipeTableView`允许自适应contentSize,就是在item的内容很少的时候,也能自适应的调整contentSize,保整至少能够滚动到顶端。5. 后期,用户的反馈header不能滑动,最后通过`UIKitDynamic`物理引擎的方式解决了这个问题。参考文章  英文博客 

开源这个项目并没有想会很多人使用,而后期,实际用到人越来越多,大家也都反映项目不能支持下拉刷新的问题,所以,便有了第二种设计方式—— 

在这个版本中,跟上面的结构原理是差不多的。由于header与bar是独立的,那么每个item就要为header与bar的空间留出空白。而在第一个设计中,是通过修改增加每个item contentInset的top值来留出顶部的留白。而几乎所有的下拉刷新空间都是不考虑inset,直接设置在content的顶部的,而contentInset是不算内容中的(一般下拉刷新控件rame的y值都是自身高度的负值)。所以,在添加了下拉刷新之后,下拉刷新组件其实是藏在header与bar的下面的,底部也正好跟bar对齐(这里可以通过调整下拉刷新组件的frame,减小y值,来显露下拉组件即可)。为了方便使用,并且兼容第三方下拉刷新,最后采用,每个item顶部的留白由tableHeaderVeiw代替(CollectionView方面要继承`STCollectionView`设置collectionHeaderView)。不过这样,item的tableHeaderView就是占用的了,由于考虑项目的简洁性,并没有自定义`UIScrollView`支持scrollview设置headerview。这样用户完全可以只是通过设置一个宏就可以支持下拉刷新,更加方便

#define ST_PULLTOREFRESH_HEADER_HEIGHT xx

其中`xx`是指下拉刷新组件RefreshHeader的高度,也就是完全显露RefreshHeader开始刷新的高度(如:`MJRefresh` 为 `MJRefreshHeaderHeight`,`SVPullToRefresh` 为 `SVPullToRefreshViewHeight`)。

最后在混合模式的时候出现了问题,最终发现,原来`UICollectionView`不支持通过contentSize属性来改变contentSize。最后只好自定义`STCollectionView`,同时支持设置collectionHeaderView,也可以实现自适应contentSize。关于`STCollectionView`的使用可以详细看github示例。

而SwipeTableView的使用方式这里不做介绍了,有兴趣的可以看看github的介绍。

总结

这是我的第一个比较完善的开源项目,在这个项目中,非常感谢使用者的认同与支持。通过这个项目,自己确实学到了很多东西,其实开这个博客也是源于这个项目的。个人觉得,对于开发者而言,能够参与一个项目,并去不断的完善解决问题,从中得到的受益将是非常大的。

最后,如果您也喜欢这个项目的话,非常欢迎您到GitHub star或者fork,您的支持是对我的最大鼓励😄

2018.03.08 更新

由于 SwipeTableView 在对 IGListKit 支持上有些问题,同时对于 Item 都是 UICollectionView 的情况也不是友好。所以,现在已经开源了一个基于 UICollectionView 的新项目 HBHybridCollectionView,实现效果类似好好住APP首页。

我的Hexo博客地址,如有转载请注明出处。

相关文章

网友评论

  • dfac6bf0166c:楼主集成后会出现内存变大的情况有怎么解决啊?
  • 生煎:你好, 横向滑动头部的时候,底部内容跟着滑动, 能不让底部滑动吗?有好的解决方法吗?
  • 秋S寂S:大神,正在下啦刷新的时候,切换index导致崩溃了,有对策吗
  • Lazyloading:我提几个用的时候遇到的问题,一个是点击在header上时候无法滑动,一个是有时候滑动时候会出现上下分离的情况很尴尬,还有就是如果第一个item的contentsize很小第二个很大的时候在切换时候会突然改变 这个问题是要自己解决吗 求回复
    roylee_stillway:如果现在用的是 master的话,建议用下3.0的分支再试试
  • c2422d697299:Header比较长,segmentbar在中间位置,滑动的时候,老是点击到segmentbar上,无法滑动。请问大神,这个怎么处理?
  • 西西西瓜:哥们,iOS11的bug修复了吗?
    lc_cat:什么bug
  • 木木123456:定义了#define ST_PULLTOREFRESH_HEADER_HEIGHT, MJ刷新加载的方法走了,但是没有出现MJ的加载菊花图
    木木123456:@roylee_stillway 使用的第三方下拉刷新控件和以前一样设置#define ST_PULLTOREFRESH_HEADER_HEIGHT xx
    roylee_stillway:@木木123456 下拉用法请参照文档。

    目前,2.x 不在维护,最新更新都在3.0分支上。请移步[SwipeTableView 3.0](https://github.com/Roylee-ML/SwipeTableView/tree/3.0),此版本去除了 STHeaderView,下拉刷新正常处理即可
    木木123456:上拉加载正常,下拉不出现菊花
  • 92a3b9a9e5b2:你好博主,请问如何监听swipetableview的偏移量呢?我需要做导航栏渐变效果。
  • c066fe49abc4:大神,下拉头视图的时候出现卡顿的话怎么办,就是下拉手势放在头视图的区域时,下拉头视图,松开手后不会自己回弹回去,但是如果下拉的手势是放在tableviewcell的区域的话,松手是可以自己回弹回去的 :joy:
  • 9ea95b711416:你好,我想请问一下,页面一开始默认是无导航栏的,就像你的demo中隐藏导航栏的情况那样,当开始上拉时导航栏逐渐显示,下拉时导航栏逐渐隐藏,导航栏完全显示后,保持swipeHeaderBar的悬停效果,该从什么方向去解决这个问题呢?我想的是当tableview的偏移量超过64时显示导航栏,但是这样的话swipeHeaderBar就没办法悬停了
    roylee_stillway:@嘿嘿嚯 你要是所有都替换了,当然就失去变量的意义,只是死的数值了。而且,我说的替换是有条件的。
    `_swipeHeaderTopInset `影响的是:初始化时顶部的位置(这里会做位置存储);adjust对齐的时候作为顶部的临界点;KVO的回调中作为顶部悬停的位置。你的需求,只需要把这些情况分开就好了,至于用什么值什么属性,你可以自己根据自己的需求定一下。
    9ea95b711416:嗯,swipeHeaderTopInset默认情况下不就是64么,把所有`_swipeHeaderTopInset`替换为64和不设置swipeHeaderTopInset的值,差别是什么呢 :smile:
    roylee_stillway:@嘿嘿嚯 这个有两种解决办法:
    1.修改一下源代码,顶部的`_swipeHeaderTopInset`设置为0。这样,默认的显示位置就是屏幕顶部对齐。但是,为了使bar悬停,所以在KVO的observer方法中,把所有`_swipeHeaderTopInset`替换为64或者自定义一个属性(这里决定了顶部悬停的位置),另外在adjust对齐item的方法中也将`_swipeHeaderTopInset`替换。
    2.不修改代码。这里取巧的可以给自己的header设置一个contentView,然后所有的子视图都布局在这里。然后这个contentView的高是实际需要的高(比如200),y值是-64,然后自己的heade的高度设置为200 - 64。这样,看上去header就是屏幕顶部对齐了。不过,这样可能出现顶部64的位置header的事件无法接受的情况。所以,最好还是第一种,改上面两处的代码,添加一个自定义需要悬停位置的属性。
  • roylee_stillway:下拉刷新的时候,你的MJ的状态是有变化的吗?如果可以,你能把你的问题发个截图或者gif到我的邮箱roylee.stillway@gmail.com。我帮你看一下
    若锦:@roylee_stillway 嗯,谢谢啦,发你邮箱了,有空的时候帮我看看 :joy:
  • roylee_stillway:你能具体说下你的问题吗?是下拉之后没有反应,跟没有加刷新一样,还是别的什么情况?
    若锦:@roylee_stillway 我定义了宏之后把mj刷新加载的方法写了,但是没有出现mj的加载菊花图,打断点发现它没有走mj的刷新加载的block :fearful:
  • 若锦:你好,我想问一下,我定义了#define ST_PULLTOREFRESH_HEADER_HEIGHT 54.0 但是并没有能够使用mj的刷新加载,是什么原因呢 :smile:
  • SilenceZhou:请问下大神你的gif制作用的工具名字是啥?
    VV木公子:@SilenceZhou 你可以用licecap 这款软件
    roylee_stillway:@SilenceZhou 没用工具,直接代码搞的

本文标题:SwipeTableView —— 一款好用的,既能上下滚动又能

本文链接:https://www.haomeiwen.com/subject/satujttx.html