你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 從MJRefresh源碼學習上拉下刷新的基本原理

從MJRefresh源碼學習上拉下刷新的基本原理

編輯:IOS開發基礎

狀態

  • Idle 閒置狀態

  • pulling 松開就可以進行刷新的狀態

  • refreshing 正在刷新狀態

初始狀態:

1.png

Uploading 屏幕快照 2016-12-02 15.22.13_456523.png . . .]

header:Idle

footer:Idle

header的狀態變化

header在拖動中顯示出來:

2.png

屏幕快照 2016-12-02 15.38.59.png

拖拽下拉時使header開始出現在屏幕上

header開始出現 -> header完全出現在屏幕上:Idle -> Pulling

header完全出現 -> header部分出現在屏幕上:Pulling -> Idle

拖曳結束時(松手時):

3.png

屏幕快照 2016-12-02 15.39.03.png

這時是在Pulling狀態松手,所以狀態由:Pulling -> Refreshing

如果是在Idle狀態下松手,狀態不改變。

footer的狀態變化

4.png

屏幕快照 2016-12-02 15.39.09.png

將要出現footer,此時footer狀態為Idle

5.png

屏幕快照 2016-12-02 15.39.13.png

footer由開始出現 -> footer完全出現:Idle -> Pulling

footer由完全出現 -> footer部分出現:Pulling -> Idle

拖曳結束時(松手時):

6.png

屏幕快照 2016-12-02 15.39.18.png

這是在Pulling狀態下松的手,所以狀態由:Pulling -> Refreshing

如果是在Idle狀態下松的手,狀態不變。

header和footer的實現

初始位置確定:

從原始狀態可以看出:

header是scrollView的subView,它的frame.y為-header.frame.height。

footer也是scrollView的subView,它的frame.y分為兩種情況:

  • 當contentSize.height > scrollView.frame.height時,footer.frame.y為contentSize.height

  • 當contentSize.height < scrollView.frame.height時,footer.frame.y為scrollView.frame.height

總而言之footer一定在scrollView的下方。

上面是最簡單的情況分析,可是現實中往往是下面這樣:

7.png

屏幕快照 2016-12-02 17.18.42.png

以上的示意圖可以設想一下,一個tableViewController嵌入在navigationController中,navigationController又嵌入在tabbarController中。此時tableViewController的tableView的contentInset屬性為(64,0,49,0),contentOffset為(0,-64)。64是狀態欄加導航欄的高度,49是tabbar的高度。這是tableViewController默認設的一些值。

因此添加footer時要考慮oringinalInsets,把

  • 當contentSize.height < scrollView.frame.height時,footer.frame.y為scrollView.frame.height

改為:

  • 當contentSize.height < scrollView.frame.height時,footer.frame.y為scrollView.frame.height - originalInsets.top - originalInsets.bottom

下面臨界值的確定都要考慮originalInsets

臨界值確定

確定了初始的位置後,要確定狀態之間變換的臨界線,通過KVO,監聽scrollView的contentOffset的變化。

header臨界值:

  • contentOffset.y < -originalInsets.top時,才開始顯示header

  • contentOffset.y <= -originalInsets.top - header.frame.size.height時,才完全顯示header

footer的臨界值:

當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

當contentSize.height小於showHeight時:

  • contentOffset.y > -originalInsets.top時就開始顯示footer。

  • contentOffset.y > -originalInsets.top + footer.frame.size.height時才完全顯示footer。

懸浮狀態的實現

header的懸浮

scrollView.contentInsets.top = header.frame.size.height + originalInsets.top
scrollView.contentOffset.y = - (scrollView.contentInsets.top)

header的隱藏

scrollView.contentInset.top = originalInsets.top
scrollView.contentOffset.y = -(scrollView.contentInsets.top)

footer的懸浮

當contentSize.height大於showHeight時:

8.png

屏幕快照 2016-12-02 18.18.39.png

scrollView.contentInsets.bottom = footer.frame.size.height + originalInsets.bottom
scrollView.contentOffset.y = contentSize.height - showHeight - originalInsets.top + footer.frame.size.height

當contentSize.height小於showHeight時:

9.png

屏幕快照 2016-12-02 18.01.38.png

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

當contentSize.height > showHeight時:

scrollView.contentOffset.y = contentSize.height - showHeight - originalInsets.top

當contentSize.height < showHeight時:

scrollView.conentOffset.y = -originalInsets.top

UIScrollView屬性詳解:

坐標系正方向:

1.png

屏幕快照 2016-12-02 15.22.01.png

ContentOffset的表示:

2.png

屏幕快照 2016-12-02 15.22.13.png

3.png

屏幕快照 2016-12-02 15.22.06.png

ContentInsets的表示:

contentInsets並不影響contentSize:

1.png

屏幕快照 2016-12-02 15.22.54.png

contentInsets影響contentOffset:

2.png

屏幕快照 2016-12-02 15.23.11.png

上圖的contentOffset為

(0, 0)

1.png

屏幕快照 2016-12-02 15.23.16.png

上圖的contentOffset為

(-contentInsets.left, -contentInsets.top)

1.png

屏幕快照 2016-12-02 15.23.21.png

上圖的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;

在沒有設置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地址

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved