狀態(tài)
Idle 閑置狀態(tài)
pulling 松開就可以進行刷新的狀態(tài)
refreshing 正在刷新狀態(tài)
初始狀態(tài):
header:Idle
footer:Idle
header的狀態(tài)變化
header在拖動中顯示出來:
拖拽下拉時使header開始出現(xiàn)在屏幕上
header開始出現(xiàn) -> header完全出現(xiàn)在屏幕上:Idle -> Pulling
header完全出現(xiàn) -> header部分出現(xiàn)在屏幕上:Pulling -> Idle
拖曳結(jié)束時(松手時):
這時是在Pulling狀態(tài)松手触创,所以狀態(tài)由:Pulling -> Refreshing
如果是在Idle狀態(tài)下松手急鳄,狀態(tài)不改變刘急。
footer的狀態(tài)變化
將要出現(xiàn)footer锚烦,此時footer狀態(tài)為Idle
footer由開始出現(xiàn) -> footer完全出現(xiàn):Idle -> Pulling
footer由完全出現(xiàn) -> footer部分出現(xiàn):Pulling -> Idle
拖曳結(jié)束時(松手時):
這是在Pulling狀態(tài)下松的手守伸,所以狀態(tài)由:Pulling -> Refreshing
如果是在Idle狀態(tài)下松的手,狀態(tài)不變。
header和footer的實現(xiàn)
初始位置確定:
從原始狀態(tài)可以看出:
header是scrollView的subView累盗,它的frame.y為-header.frame.height害淤。
footer也是scrollView的subView觉增,它的frame.y分為兩種情況:
當(dāng)contentSize.height > scrollView.frame.height時,footer.frame.y為contentSize.height
當(dāng)contentSize.height < scrollView.frame.height時斋陪,footer.frame.y為scrollView.frame.height
總而言之footer一定在scrollView的下方。
上面是最簡單的情況分析,可是現(xiàn)實中往往是下面這樣:
以上的示意圖可以設(shè)想一下属桦,一個tableViewController嵌入在navigationController中,navigationController又嵌入在tabbarController中他爸。此時tableViewController的tableView的contentInset屬性為(64,0,49,0)聂宾,contentOffset為(0,-64)。64是狀態(tài)欄加導(dǎo)航欄的高度诊笤,49是tabbar的高度系谐。這是tableViewController默認(rèn)設(shè)的一些值。
因此添加footer時要考慮oringinalInsets讨跟,把
當(dāng)contentSize.height < scrollView.frame.height時纪他,footer.frame.y為scrollView.frame.height
改為:
當(dāng)contentSize.height < scrollView.frame.height時,footer.frame.y為scrollView.frame.height - originalInsets.top - originalInsets.bottom
下面臨界值的確定都要考慮originalInsets
臨界值確定
確定了初始的位置后晾匠,要確定狀態(tài)之間變換的臨界線茶袒,通過KVO,監(jiān)聽scrollView的contentOffset的變化凉馆。
header臨界值:
contentOffset.y < -originalInsets.top時薪寓,才開始顯示header
contentOffset.y <= -originalInsets.top - header.frame.size.height時,才完全顯示header
footer的臨界值:
當(dāng)contentSize.height大于showHeight時:
contentOffset.y > scrollView.frame.size.height - showHeight - originalInsets.top時才開始顯示footer澜共。
contentOffset.y > scrollView.frame.size.height - showHeight - originalInsets.top + footer.frame.size.height時才完全顯示footer
當(dāng)contentSize.height小于showHeight時:
contentOffset.y > -originalInsets.top時就開始顯示footer向叉。
contentOffset.y > -originalInsets.top + footer.frame.size.height時才完全顯示footer。
懸浮狀態(tài)的實現(xiàn)
header的懸浮
1
2scrollView.contentInsets.top?=?header.frame.size.height?+?originalInsets.top
scrollView.contentOffset.y?=?-?(scrollView.contentInsets.top)
header的隱藏
1
2scrollView.contentInset.top?=?originalInsets.top
scrollView.contentOffset.y?=?-(scrollView.contentInsets.top)
footer的懸浮
當(dāng)contentSize.height大于showHeight時:
1scrollView.contentInsets.bottom?=?footer.frame.size.height?+?originalInsets.bottom
2scrollView.contentOffset.y?=?contentSize.height?-?showHeight?-?originalInsets.top?+?footer.frame.size.height
當(dāng)contentSize.height小于showHeight時:
scrollView.contentInsets.bottom?=?bottom?+?showHeight?-?contentSize.height
可以理解成初始的contentOffset.y為-originalInsets.top嗦董,然后向上移動了footer.frame.size.height:
scrollView.contentOffset.y?=?-originalInsets.top?+?footer.frame.size.height
footer的隱藏
scrollVIew.contentInsets.bottom?=?originalInsets.bottom
當(dāng)contentSize.height > showHeight時:
scrollView.contentOffset.y?=?contentSize.height?-?showHeight?-?originalInsets.top
當(dāng)contentSize.height < showHeight時:
scrollView.conentOffset.y?=?-originalInsets.top
UIScrollView屬性詳解:
坐標(biāo)系正方向:
ContentOffset的表示:
ContentInsets的表示:
contentInsets并不影響contentSize:
contentInsets影響contentOffset:
上圖的contentOffset為
(-contentInsets.left,?-contentInsets.top)
上圖的contentOffset為
(contentSize.width?-?scrollView.frame.size.width?+?contentInsets.right,?contentSize.height?-?scrollView.frame.size.height?+?contentInsets.bottom)
其實contentInsets就是為scrollView提供了更多的可停留空間母谎,切記要把彈簧效果開啟,否則在contentSize小于scrollView.frame時scrollView無法拉動京革。
scrollView.alwaysBounceVertical?=?YES;
self.scrollView.alwaysBounceHorizontal?=?YES;
在沒有設(shè)置contentInsets的情況下奇唤,scrollView的停留范圍為:
contentOffset.x:?0?->?max(contentSize.width?-?scrollView.frame.width,?0)
contentOffset.y:?0?->?max(contentSize.height?-?scrollView.frame.height,?0)
在有contentInsets的情況下供璧,scrollView的停留范圍為:
contentOffset.x:?-contentInsets.left?->?max(contentSIze.width?-?scrollView.frame.size.width)?+?contentInsets.right
contentOffset.y:?-contentInsets.top?->?max(contentSIze.height?-?scrollView.frame.size.height)?+?contentInsets.bottom
demo地址