UITableView 編輯模式詳解

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);

beginUpdatesendUpdates兩個方法,在你需要批量處理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在編輯模式下左側是否縮進。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容