本文將說明讓uiscrollview支援"下拉重新整理"和"上拉載入更多"的實現機制,並實現乙個可用的tableview子類,以下主要以"下拉重新整理"進行說明。
工程位址在帖子最下方,只需要**的直拉到底即可。
1、contentinset和下拉重新整理
contentinset是uiscrollview的屬性,它描述了uiscrollview的內容view的內邊距,具體可見官方文件:
目前幾乎所有"下拉重新整理"的第三方庫都是依賴它實現的。
【為便於討論,將下拉重新整理/上拉載入時顯示的檢視稱為refresh panel,如下圖】
在使用者手指向下滑動到最終更新介面的過程中,經歷了4個步驟:
(1)隨著使用者下拉逐漸顯示uitableview頂部的refresh panel;
(2a)下拉達到預設位置,狀態文字變為"鬆開可以重新整理";
(2b)下拉未達到預設位置,使用者手指離開螢幕,scrollview彈回,refresh panel重新隱藏起來,結束。
(3)使用者手指離開螢幕,refresh panel保持顯示。狀態文字變為"載入中",在後台執行更新資料的操作;
(4)資料更新完成,返回主線程,重新隱藏refresh panel,結束。
可以看到,如果不考慮重新整理時間、狀態文字等,實現"下拉重新整理"實際上只需要做到2件事:
(1)隱藏refresh panel(初始時和重新整理後)
隱藏refresh panel,即使其居於uitableview的上方且不可見,如下
1
- (void
)adddragheaderview2
11 }
【 注意 :不應使用uitableview的tableheaderview來作為refresh panel,一來會使得下拉重新整理和自定義tableheaderview無法共存,二來uitableview的內容檢視是包含tableheaderview的,即
tableview.contentsize.height == tableview.tableheaderview.height
+ n * sectionheaderview.height
+ m * cell.height
+ tableview.tablefooterview.height
因此想讓tableheaderview預設不可見,需要修改contentoffset的初始值並在使用者滑動時控制滑動範圍,非常麻煩。】
(2)顯示refresh panel
當使用者手指下拉達到預設值並離開螢幕,立即修改contentinset,使refresh panel保持顯示,如下
1
- (void)scrollviewdidenddragging:(uiscrollview *)scrollview willdecelerate:(bool)decelerate2
8 }
如此,更新資料後再次隱藏refresh panel的方式也很明了
1 self.contentinset = uiedgeinsetszero;
2、動畫、動態文字和重新整理時間
1在1中已經做到了refresh panel的顯示的隱藏,2中只需要在合適的時候改變refresh panel的顯示內容即可。@implementation
pull2refreshview
2
(1)"下拉可以重新整理"—>"鬆開立即更新"
在uiscrollview的委託函式scrollviewdidscroll:中檢測使用者下拉的程度,達到預設值後就改變狀態,如下:
1
- (void)scrollviewdidscroll:(uiscrollview *)scrollview2
14 }
15 }
修改指示箭頭方向為向上,在setstate中修改狀態文字為"鬆開立即重新整理"。
(2)"鬆開立即重新整理"—>"載入中..."
在uiscrollview的委託函式scrollviewdidenddragging: willdecelerate:中檢測使用者手指離開螢幕時的情況:
1
- (void)scrollviewdidenddragging:(uiscrollview *)scrollview willdecelerate:(bool)decelerate2
12 }
相比1中新增了修改指示箭頭方向,在setstate中修改狀態文字為"載入中..."。
(3)"載入中..."—>"下拉可以重新整理"
這一步需要由外部(通常是viewcontroller)判斷何時執行,提供乙個方法供外部呼叫,如下:
1
- (void
)completedragrefresh
2
指示箭頭方向和狀態文字恢復為初始狀態,更新時間變為當前時間。
3、其他
(1)"下拉重新整理"和"上拉載入更多"的不同
"下拉重新整理"的refresh panel的位置始終不變,而"上拉載入更多"的refresh panel則需要隨著tableview.contentsize的變化而變化。乙個比較簡單的方案是:
1 tableview.tablefooterview = dragfooterview;在某些第三方實現中便是如此處理的,好處是簡單到只需要一行**,壞處是tablefooterview被占用了。考慮到tablefooterview在"上拉載入更多"的情境下不太需要自定義,影響不大。
另乙個方案是在初始化時和資料更新後,設定refresh panel的frame使其始終保持正確位置。
此外,在觸發重新整理的條件上,二者也是不同的。"下拉重新整理"時,為防止重新整理"太過靈敏",需要設定乙個閥值來控制,所以才有"鬆開立即重新整理"。而"上拉載入更多"是在使用者往下不斷瀏覽內容的過程中觸發的,因此只需滑動到內容底部就立即觸發載入。
uitableview作為派生類,是和基類uiscrollview共享乙個delegate屬性的,即uitableviewdeleagte和uiscrollviewdelegate是同時指定的。這帶來的問題是,想要封裝乙個支援"下拉重新整理"和"上拉載入更多"的uitableview子類,恐怕不得不增加一層委託,將uitableviewdelegate中的各種方法都轉到外部進行實現,如
1
- (void)tableview:(uitableview *)tableview didselectrowatindexpath:(nsindexpath *)indexpath2
7 }
可謂麻煩至極。暫未想到較好的解決方案。【mark】
4、封裝的pull2refreshtableview demo工程
使用ios 6.1 sdk編譯,使用arc。
1、scroll view programming guide for ios
UITableView實現下拉重新整理
uirefreshconteol類是實現下拉重新整理的控制項,並且uitableview有refreshcontrol的屬性。定義 uirefreshcontrol control uirefresh alloc init 下拉重新整理時顯示的文字 control.attributedtitle n...
UITableView實現下拉重新整理的小功能
一 找到你的 uitableview uitableviewcontroller 的 h 檔案,結合以下 新增相應的元素 import egorefreshtableheaderview.h inte ce rootviewcontroller uitableviewcontroller void ...
UITableView實現下拉重新整理新增資料功能
用uitableviewdelegate中的這個方法 void tableview uitableview tableview willdisplaycell uitableviewcell cell forrowatindexpath nsindexpath indexpath 判定tablevi...