不知道有没有细心的同学注意,App Store首页、知乎发现也的头部在下拉的时候是不动的,上推得时候会和列表一起无视差上滑动。如下图。
微信 知乎 App Store那么这些效果是怎么实现的呢?
分析
微信图1 微信图2根据微信图1,我们暂且假设蓝色框内部分用UICollectionView
实现的,但是根据滑条在红色框内那块视图的下面,我们可以推断出,红色框内的视图不是注册的UICollectionView
的headerView
。他应该是直接add在我们假设的UICollectionView
,或者UICollectionView
的superView
上的。
再看微信图2滑条的位置,正好在红色框那块视图的下方。这是怎么实现的呢?
open var scrollIndicatorInsets: UIEdgeInsets // default is UIEdgeInsetsZero. adjust indicators inside of insets
就是这个接口,只要像这样设置一下tableView.scrollIndicatorInsets.top = 130
那么滑条就会偏移130pt。
知道了这个关键的接口,那么微信图中的那种header效果实现思路就基本很清晰了。
思路
- 通过
UICollectionViewFlowLayout
的headerReferenceSize
方法空出你头部的size - 通过
scrollIndicatorInsets
这个接口设置滑条的位置 - 把视图添加到你的滚动视图上
现在微信头部的效果基本可以完成了,那知乎的呢?其实是差不多的,就是知乎在下拉的时候是不动的。
接着微信的那个思路,我们很容易想到在下拉的时候控制headerView
的y值即可。
核心代码
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// 204 = headerView.frame.height + 导航栏和状态栏高度
let y = scrollView.contentOffset.y
headerView.frame.origin.y = 64 - 204 - max(y, -204)
}
我们再看App Store的那个效果。咦,他的滑条怎么在headerView
的上方?显然之前的思路和这个效果相驳。
分析
- 如果要满足滑条在
headerView
的上方的条件,那么headerView
应该是加在tableHeaderView
上的(有实现相同效果的其他方案请留言)。 - 如果又要满足下拉时
headerView
不动,那么他又不应该是加在tableHeaderView
,因为tableHeaderView
的坐标是不能改的。(因为我们知道的太少了,所以改不了)
思考
如果满足一,肯定满足不了二。满足二又不满足一。我的脑子里最开始是这么想的。
再对两个条件比较,想要满足滑条在视图上方我只有条件一那种方式做的到,只要我在合适的地方修改到tableHeaderView
的位置就能满足条件二了。
第一次尝试
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
let y = scrollView.contentOffset.y
tableView.tableHeaderView?.frame.origin.y = 64 - 204 - max(y, -204)
}
显然是失败的。
Google。。。
找到了这个
在里面发现了这个方法
func viewDidLayoutSubviews(){}
似曾相识,但是又不是。
相信之前很多人用过这个方法
func layoutSubviews() {}
如果你不熟悉这个方法,请跳转
第二次尝试
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// 64应该为状态栏和导航栏高度
// automaticallyAdjustsScrollViewInsets这个属性默认为true,一个UIScrollView在有导航栏的控制器中,坐标会从导航栏底部计算
let y = tableView.contentOffset.y
if y <= -64 {
tableView.tableHeaderView?.frame.origin.y = y + 64
}
}
网友评论