UITableView:下拉重新整理和上拉載入更多
【轉載請註明出處】
本文將說明具有多個section的UITableView在使用下拉重新整理機制時會遇到的問題及其解決方案。
工程地址在帖子最下方,只需要程式碼的直拉到底即可。
【目錄】
1、現象分析;
2、解決方案;
3、工程地址。
1、現象分析
當前的大多數支援下拉重新整理的庫,都是通過修改UIScrollView的contentInset實現的。
(可參見我的這篇帖子:UITableView:下拉重新整理和上拉載入更多)
使用這種方法帶來的問題是,當UITableView具有多個section時,依照上述方式使用下拉重新整理,在載入過程中上滑,會出現樣式跑版:
為了分析出問題所在,首先在控制檯列印出正常狀態下UITableView的所有子View :
比較各行的frame.origin.y可以看出,UITableView的section headerView是和cell一起,按順序放入基類UIScrollView的內容View中的。
再看載入中時的情況:
從Pull2RefreshView的frame可以看出,此時UITableView的contentInset已經被修改為(65, 0, 0, 0)。而section headerView和各個cell的frame.origin.y不受影響,和預期一致。
最後看看在載入中狀態下上滑時的情況,將UITableView上滑至上方圖中所示情境,即第一行的cell剛剛好越過section headerView:
可以看到,section headerView的frame.origin.y發生了變化,它和第二個cell一起被放在了第一個cell的下方,即:
section headerView.frame.origin.y == firstCell.frame.origin.y + cellHeight;
繼續上滑,可以看到section headerView.frame.origin.y不斷變化,但在介面顯示上,始終位於距離UITableView.frame.origin.y為65(即修改後contengInset.top的值)的位置,直到下一個section headerView出現時,才隨著cell向上移動,如圖:
【注意:不論在任何情況下,第一個cell的frame.origin.y始終為section headerView的高度,在本例中為23,即使它已經處於section headerView的上方】
2、解決方案
由此,可以粗略得出以下結論:
A、 section headerView和cell之間並不是簡單的順序擺放的關係,它們之間可以發生重疊;
B、 section headerView在介面上的顯示位置由UITableView.contentInset.top決定,直到被下一個section headerView替代。
如此,想要在滑動時修改section headerView的顯示位置,令其和cell一起移動,只需要動態地修改UITableView.contentInset.top即可,如下:
2 {
3 //added 2013.11.28 動態修改headerView的位置
4 if (headerRefreshing)
5 {
6 if (scrollView.contentOffset.y >= -scrollView.contentInset.top
7 && scrollView.contentOffset.y < 0)
8 {
9 //注意:修改scrollView.contentInset時,若使當前介面顯示位置發生變化,會觸發scrollViewDidScroll:,從而導致死迴圈。
10 //因此此處scrollView.contentInset.top必須為-scrollView.contentOffset.y
11 scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
12 }
13 else if (scrollView.contentOffset.y == 0)//到0說明headerView已經在tableView最上方,不需要再修改了
14 {
15 scrollView.contentInset = UIEdgeInsetsZero;
16 }
17 }
18
19 //other code here...
20 }
Added 2014.7.24:
對於不需要提交到AppStore的應用,還有一個更簡單的辦法,即覆蓋UITableView的私有方法。
- (BOOL)allowsHeaderViewsToFloat { return NO; } - (BOOL)allowsFooterViewsToFloat { return NO; }
3、工程地址
使用iOS 6.1 SDK編譯,使用ARC。
地址:https://github.com/cDigger/CDPullToRefreshDemo
【參考】
1、Section Headers in UITableView when inset of tableview is changed
2、Change Default Scrolling Behavior of UITableView Section Header