UITableView 編輯模式詳解
UITableView
的相關編輯操作非常全,今天我們來做一個總結。跟編輯相關的屬性和接口有如下,我們一個一個分析,我們先認真閱讀一下相關頭文件,我根據意思大概翻譯了一下注釋。
屬性方法
@property (nonatomic, getter=isEditing) BOOL editing;
// 默認狀態是非編輯狀態,如果不調用下面接口直接設置,是沒有動畫的
- (void)setEditing:(BOOL)editing animated:(BOOL)animated;
DataSource
// 當增減按鈕按下時,用來處理數據和UI的回調。
// 8.0版本后加入的UITableViewRowAction不在這個回調的控制范圍內,UITableViewRowAction有單獨的回調Block。
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
// 這個回調實現了以后,就會出現更換位置的按鈕,回調本身用來處理更換位置后的數據交換。
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
// 這個回調決定了在當前indexPath的Cell是否可以編輯。
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
// 這個回調決定了在當前indexPath的Cell是否可以移動。
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath;
Delegate
// 這個回調很關鍵,返回Cell的編輯樣式。
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
// 刪除按鈕的文字
- (nullable NSString *)tableView:(UITableView *)tableView titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(3_0) __TVOS_PROHIBITED;
// 8.0后側滑菜單的新接口,支持多個側滑按鈕。
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath NS_AVAILABLE_IOS(8_0) __TVOS_PROHIBITED;
// 這個接口決定編輯狀態下的Cell是否需要縮進。
- (BOOL)tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;
// 這是兩個狀態回調
- (void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath __TVOS_PROHIBITED;
- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath __TVOS_PROHIBITED;
編輯狀態
UITableView
通過editing屬性控制編輯狀態,調用- (void)setEditing:(BOOL)editing animated:(BOOL)animated
接口,可以決定是否使用原生的變換動畫。
當調用這個接口,并將editing設為YES
是,UITableView
將開始詢問代理(Delegate)需要編輯哪些Cell,用什么樣的方式編輯。
首先調用回調方法- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath;
,這里需要返回YES;
然后依次為各個Cell調用- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;
方法獲取編輯樣式。
typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) {
UITableViewCellEditingStyleNone,
UITableViewCellEditingStyleDelete,
UITableViewCellEditingStyleInsert
};
編輯樣式枚舉有三種,位運算組合則由不同的用途。
UITableViewCellEditingStyleNone 沒有編輯樣式
UITableViewCellEditingStyleDelete 刪除樣式 (左邊是紅色減號)
UITableViewCellEditingStyleInsert 插入樣式 (左邊是綠色加號)
UITableViewCellEditingStyleDelete|UITableViewCellEditingStyleInsert 多選模式,左邊是藍色對號
特別注意,右邊的移動并不是這里控制的,需要實現下面這個回調才會出現。
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath toIndexPath:(NSIndexPath *)destinationIndexPath;
另外對于新手來說,要明白這里的回調都沒有對UI和數據進行操作,開發者需要在回調中,完成相應的操作。比如刪除或者添加一條數據,應在
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath;
上面這個回調中,根據editingStyle進行判斷,處理對應的UI和數據。
數據與UI更新
數據更新沒什么好說的,直接操作數據容器就好,無論是數組、字典還是CoreData數據。UI更新則需要使用TableView的方法,如果需求reloadData無法滿足,則必須使用下面的方法
- (void)beginUpdates; // allow multiple insert/delete of rows and sections to be animated simultaneously. Nestable
- (void)endUpdates; // only call insert/delete/reload calls or change the editing state inside an update block. otherwise things like row count, etc. may be invalid.
- (void)insertSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
- (void)moveSection:(NSInteger)section toSection:(NSInteger)newSection NS_AVAILABLE_IOS(5_0);
- (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)deleteRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;
- (void)reloadRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation NS_AVAILABLE_IOS(3_0);
- (void)moveRowAtIndexPath:(NSIndexPath *)indexPath toIndexPath:(NSIndexPath *)newIndexPath NS_AVAILABLE_IOS(5_0);
beginUpdates
和endUpdates
兩個方法,在你需要批量處理Cell的時候,用來包裹住你的處理代碼,其他方法名字都很直觀,不一一介紹了。
最后給大家推薦一個Cocoa框架里的功能強大的類NSFetchedResultsController
,用于綁定CoreData數據和UITableView
或者UICollectionView
,直接封裝好所有的UI操作代碼,只要數據有變動,UI自動更新,爽的不要不要的,媽媽再也不用擔心我的TableView寫不好了,下一篇文章我準備詳細講一講這個有趣的類。
2017.11.29更新
感謝簡單程序媛
同學的發問,在此補充一個回調,用于只使用tableView右側排序功能,而不顯示左側刪除和插入,并且左側不留白的方法
- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
return UITableViewCellEditingStyleNone;
}
- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
return NO;
}
UITableViewCellEditingStyleNone
隱藏了左側編輯按鈕,shouldIndentWhileEditingRowAtIndexPath控制cell在編輯模式下左側是否縮進。