用UICollectionView实现多表联调滑动。
引言
最近接了一个需求,要实现多表联动滑动的效果,同时需要支持菜单栏置顶,下拉刷新功能。特此记录遇到的坑。
先看实现效果。
方案一
实现多表滑动的时候,首先想到的是用系统的UIPageViewController,可以方便的为我们管理controller的生命周期。但这个类已被高度封装,无法获取内部scrollview的属性和scroll的偏移值(也可以获取,就是有点麻烦),同时子controller出现的时机也难以把握。更重要的是 有一些坑,比如快速滑动 与 快速点击的时候,有时候会崩溃。所以这个方案不可行。
方案二
使用UICollectionView,可以获取子view的滑动值,但必须自己控制生命周期。即封装成一个UIPagecontroller。故采用这种方案。
实现
1、用UICollectionView实现左右滑动,设置cell的大小为当前屏幕的大小,这样每切换滑动一次可以切换一个cell,即
itemSize = self.view.size
2、为了将多个子列表解耦,必须为每个列表单独创建一个VC。通过addChildController、removeController的方式,显示VC对应的View。
这个有两个坑
1、复用UICollectionViewCell的时候 需要清除之前的VC 和 VIew。对应的VC可以通过nextreponder 的方式寻找。
2、当UICollectionView滑动停止的时候,需要清除当前不在显示区域的VC 和 view。保证只有一个VC和对应的view显示。
3、为了显示顶部的悬浮菜单栏TopView,并且不跟随UICollectionView左右滑动,故设置跟UICollectionView同级。
4、TopView会盖住子列表的部分内容,还需要设置子列表的contentInset.top = TopView.frame.height
完成以上四步,框架基本搭建完成,下面将逐一解决遇到的问题。
###问题###
可以在TopView上添加一个监听上下滑动的UIPanGesture手势。TopView有可能会展示左右滑动的banner,所以在触发手势的时候,需要判断是否是上下滑动手势。如果是则联动子列表一起滑动
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer == self.panGesutre {
let point = self.panGesutre.translation(in: self)
if abs(point.y) > abs(point.x) {
return true
}
return false
}
return true
}
通常情况下在我们会在viewdidload调用 mjheader.beginRefresh()。该方法会使得当前列表偏移 cotentInset.top + 刷新控件.height。并产生下拉动画。该动画会联动TopView一起滑动。,如果第一次显示页面时,不是在原先设定的初始位置,此动画有可能导致TopView无法固定悬浮。目前也只能暂时规避,不调用mj_header.beginRefresh(),自定义刷新。
reloadData()
tableView.layoutIfNeeded() //进行强制刷新