不知道有沒有細心的同學注意,App Store首頁、知乎發(fā)現(xiàn)也的頭部在下拉的時候是不動的,上推得時候會和列表一起無視差上滑動。如下圖。



那么這些效果是怎么實現(xiàn)的呢?
分析
根據(jù)微信圖1,我們暫且假設藍色框內(nèi)部分用UICollectionView實現(xiàn)的,但是根據(jù)滑條在紅色框內(nèi)那塊視圖的下面,我們可以推斷出,紅色框內(nèi)的視圖不是注冊的UICollectionView的headerView。他應該是直接add在我們假設的UICollectionView,或者UICollectionView的superView上的。
再看微信圖2滑條的位置,正好在紅色框那塊視圖的下方。這是怎么實現(xiàn)的呢?
open var scrollIndicatorInsets: UIEdgeInsets // default is UIEdgeInsetsZero. adjust indicators inside of insets
就是這個接口,只要像這樣設置一下tableView.scrollIndicatorInsets.top = 130那么滑條就會偏移130pt。
知道了這個關鍵的接口,那么微信圖中的那種header效果實現(xiàn)思路就基本很清晰了。
思路
- 通過
UICollectionViewFlowLayout的headerReferenceSize方法空出你頭部的size - 通過
scrollIndicatorInsets這個接口設置滑條的位置 - 把視圖添加到你的滾動視圖上
現(xiàn)在微信頭部的效果基本可以完成了,那知乎的呢?其實是差不多的,就是知乎在下拉的時候是不動的。
接著微信的那個思路,我們很容易想到在下拉的時候控制headerView的y值即可。
核心代碼
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// 204 = headerView.frame.height + 導航欄和狀態(tài)欄高度
let y = scrollView.contentOffset.y
headerView.frame.origin.y = 64 - 204 - max(y, -204)
}
我們再看App Store的那個效果。咦,他的滑條怎么在headerView的上方?顯然之前的思路和這個效果相駁。
分析
- 如果要滿足滑條在
headerView的上方的條件,那么headerView應該是加在tableHeaderView上的(有實現(xiàn)相同效果的其他方案請留言)。 - 如果又要滿足下拉時
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。。。
找到了這個
在里面發(fā)現(xiàn)了這個方法
func viewDidLayoutSubviews(){}
似曾相識,但是又不是。
相信之前很多人用過這個方法
func layoutSubviews() {}
如果你不熟悉這個方法,請跳轉(zhuǎn)
第二次嘗試
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// 64應該為狀態(tài)欄和導航欄高度
// automaticallyAdjustsScrollViewInsets這個屬性默認為true,一個UIScrollView在有導航欄的控制器中,坐標會從導航欄底部計算
let y = tableView.contentOffset.y
if y <= -64 {
tableView.tableHeaderView?.frame.origin.y = y + 64
}
}
效果
