概述
直接切入正題,最近公司項目迭代,要實現帶頭圖的tabelView的刷新,其實也沒什么,但是刷新的地方不在頭部的上方,而是放在了頭部視圖的下方,效果如下:
有點tableView的組刷新的錯覺。頭部視圖跟隨tableView的滾動一起聯動,下拉完成刷新,上拉實現加載更多。
方案探索
界面這樣設計也是有一定道理的,因為頭部視圖占據了很大一部分的空間,如果將其固定,那么用戶所能看到的內容就會在頭部視圖以下的位置了,這樣體驗很不友好。但是如果將它放在了tableView
的頭部,那么問題又來了,刷新放在了tableView的頂部,刷新的時候頂部會出現大片空白并且頭部視圖還因此偏移,整體畫面很不好看。所以最終選擇了當前的設計:在頭部視圖下面添加對應的刷新,而用戶在瀏覽內容的時候,將頭部視圖動態隱藏掉,這就有點像tableView的刷新放在了sectionHeader
的下面(顯然是一種錯覺嘛),所以為了實現上面的兩種效果,我想了兩種方案,分享一下:
在說這兩種方案之前,先說一下界面的構造,頭部視圖實際上不在tableView的header上面,而是單獨的放在了controller的view上,與tableView位于同一層次,tableView在頭部視圖的下面
方案一:使用動畫過渡來隱藏頭圖,達到瀏覽空間的拓展。
實現這樣的效果,可以在tableView
滾動的時候進行scrollView
的內容偏移量contentOffset
的監聽,我們都知道,contentOffset.y
的值隨著滾動方向的不同發生不同的變化,下滑y
值會隨之變大,上滑y
值減少(有些時候可以通過該特性進行上滑、下滑的判斷)。scrollView
中有一個對應滾動的回調scrollViewDidScroll:(UIScrollView *)scrollView
,通過該回調,拿到對應的y
值。此時對當前的y
值進行判斷,如果y>0,那么對headerView進行約束的更新,當然這個更新不能直接將tableView偏移到頂部,這樣會出現跳躍感,為了讓界面看起來過渡友好,可以用動畫來解決,如下:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat contentOffsetY = scrollView.contentOffset.y;
if (contentOffsetY > 0) {
//隱藏頂部img
if (!self.isHidden) {
[UIView animateWithDuration:0.25 animations:^{
[self.tableView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(0);
}];
[self.tableView layoutIfNeeded];
}];
self.isHidden = YES;
}
}else{
//顯示頂部img
if (self.isHidden) {
[UIView animateWithDuration:0.25 animations:^{
[self.tableView mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(202);
}];
[self.tableView layoutIfNeeded];
}];
self.isHidden = NO;
}
}
}
效果如下:
方案二:利用約束更新,實時更新頂部的頭圖位置,保證它與tableView的滾動協調,進而過渡自然
也是利用了scrollView的滾動回調的偏移量來進行約束的更新,由于更新分三種情況:
- 偏移量y<0,處于下拉刷新狀態,應該恢復頭部起始位置
- 偏移量y>=0 && y<=topImg.height,處于劃滾動瀏覽狀態,應該適當隱藏頭部imgView
- 偏移量 y>topImg.height,處于完全瀏覽狀態。應該完全隱藏掉頭部imgView
實現如下:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
CGFloat offsetY = scrollView.contentOffset.y;
//偏移量在頂部image的高度以內
if (offsetY <= 202 & offsetY > 0) {
[self.topImg mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(-offsetY);
}];
}else if(offsetY > 202){ //大于頂部頭部高度,固定頂部的高度
if (self.topImg.frame.origin.y == -202) {
return;
}
[self.topImg mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(-202);
}];
}else if(offsetY < 0){
[self.topImg mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.mas_equalTo(0);
}];
}
}
效果如下:
總結
對于上述兩種實現方案,最終所達成的效果都差不多,選擇也是根據項目的需求來定的,同時也希望能為需要實現該效果的同學一點靈感。