iOS文檔補完計劃--UITableViewDataSource&&UITableViewDelegate

目錄主要分爲以下幾個樣式:
常用、會用、瞭解

目錄

  • UITableViewDataSource
  • 配置TableView
    • tableView:cellForRowAtIndexPath:
    • tableView:numberOfRowsInSection:
    • numberOfSectionsInTableView:
    • tableView:titleForHeaderInSection:
    • tableView:titleForFooterInSection:
  • 插入&&刪除
    • tableView:commitEditingStyle:forRowAtIndexPath:
    • tableView:canEditRowAtIndexPath:
  • 重新排序
    • tableView:canMoveRowAtIndexPath:
    • tableView:moveRowAtIndexPath:toIndexPath:
  • 索引設置
    • sectionIndexTitlesForTableView:
    • tableView:sectionForSectionIndexTitle:atIndex:
  • UITableViewDelegate
  • 配置Row
    • tableView:heightForRowAtIndexPath:
    • tableView:estimatedHeightForRowAtIndexPath:
    • tableView:indentationLevelForRowAtIndexPath:
    • tableView:willDisplayCell:forRowAtIndexPath:
    • tableView:shouldSpringLoadRowAtIndexPath:withContext:
  • 擴展按鈕
    • tableView:editActionsForRowAtIndexPath:
    • tableView:accessoryButtonTappedForRowWithIndexPath:
  • 選擇管理
    • tableView:willSelectRowAtIndexPath:
    • tableView:didSelectRowAtIndexPath:
    • tableView:willDeselectRowAtIndexPath:
    • tableView:didDeselectRowAtIndexPath:
  • 頁眉和頁腳
    iOS11需要注意的新特性
  • 編輯表單(左滑)
    • tableView:willBeginEditingRowAtIndexPath:
    • tableView:didEndEditingRowAtIndexPath:
    • tableView:editingStyleForRowAtIndexPath:
    • tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:
    • tableView:shouldIndentWhileEditingRowAtIndexPath:
  • 重新排序表單
    • tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:
  • 移動出可見範圍
    • cell/sectionHeaderView/sectionFooterView的消失
  • MENU菜單
  • 高亮管理

UITableViewDataSource

一個能夠爲UITableView提供展示要素的代理


配置TableView

  • tableView:cellForRowAtIndexPath:

將返回的Cell插入TableView的indexPath位置。(一旦需要展示cell)則必須實現且不能返回nil。

- (UITableViewCell *)tableView:(UITableView *)tableView 
         cellForRowAtIndexPath:(NSIndexPath *)indexPath;

返回的對象通常是重用的cell。

  • - tableView:numberOfRowsInSection:

返回該節有多少行內容(必須實現

- (NSInteger)tableView:(UITableView *)tableView 
 numberOfRowsInSection:(NSInteger)section;
  • numberOfSectionsInTableView:

返回一共有多少節內容需要展示

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;

默認返回1

  • - tableView:titleForHeaderInSection:
  • - tableView:titleForFooterInSection:

爲系統默認樣式的sectionHeader/sectionFooter設置文字

- (NSString *)tableView:(UITableView *)tableView 
titleForHeaderInSection:(NSInteger)section;

除了敲demo通常沒啥用。你應該使用tableView:viewForHeaderInSection:進行自定義樣式。


插入&&刪除

  • - tableView:commitEditingStyle:forRowAtIndexPath:

編輯完成時調用

- (void)tableView:(UITableView *)tableView 
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
forRowAtIndexPath:(NSIndexPath *)indexPath;

如果點擊其他地方被取消、則不會被調用。

editingStyle是一個枚舉、有三種可能的值

typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) {
    UITableViewCellEditingStyleNone,//沒有編輯樣式
    UITableViewCellEditingStyleDelete,//刪除樣式 (左邊是紅色減號)
    UITableViewCellEditingStyleInsert//插入樣式  (左邊是綠色加號)
};

當你進行了對應的操作(點擊了綠色的添加或者紅色的刪除)、代理將會告知你並讓你修改數據源以配合操作。

  • - tableView:canEditRowAtIndexPath:

返回該位置的cell是否可以進入編輯狀態

- (BOOL)tableView:(UITableView *)tableView 
canEditRowAtIndexPath:(NSIndexPath *)indexPath;

如果沒有實現此方法、那麼默認所有的cell都可以進入編輯狀態。
這個編輯狀態有兩種意思:

  1. 通過[self.tableView setEditing:YES animated:YES];讓所有cell進入
  2. 右滑

重新排序

讓tableView支持拖動、需要以下條件

  1. 讓tableView進入編輯狀態
    也就是設置它的editing爲YES

  2. 返回編輯模式
    也就是實現UITableViewDelegate中的tableview:editingStyleForRowAtIndexPath:方法,在裏面返回UITableViewCellEditingStyleNone模式。如果不實現,默認返回的就是刪除模式

3、實現tableView:moveRowAtIndexPath:toIndexPath方法
只要實現該方法,就能實現單元格的拖動排序,但只是實現了表面的排序,並沒有修改真實地數據

4、在方法中完成數據模型的更新

  • tableView:canMoveRowAtIndexPath:

是否可以將該cell拖動到指定位

- (BOOL)tableView:(UITableView *)tableView 
canMoveRowAtIndexPath:(NSIndexPath *)indexPath;

返回該單元格、是否可以被拖動。默認返回YES。

  • - tableView:moveRowAtIndexPath:toIndexPath:

拖動完成時觸發、讓用戶修改數據源

- (void)tableView:(UITableView *)tableView 
moveRowAtIndexPath:(NSIndexPath *)sourceIndexPath 
      toIndexPath:(NSIndexPath *)destinationIndexPath;

如果不做修改、cell就僅僅是在當前展示上修改了位置。下次被提取或者刷新時會變回原來的順序。


索引設置

  • - sectionIndexTitlesForTableView:

返回索引數組

- (NSArray<NSString *> *)sectionIndexTitlesForTableView:(UITableView *)tableView;
  1. tablbView的style必須是UITableViewStylePlain
  2. 返回的數組將會懸浮在tableView右側
  • - tableView:sectionForSectionIndexTitle:atIndex:

點擊索引後、將talbeView移動至哪個section處

- (NSInteger)tableView:(UITableView *)tableView 
sectionForSectionIndexTitle:(NSString *)title 
               atIndex:(NSInteger)index;

支持數組越界


UITableViewDelegate

對頁眉頁腳、高度、選擇、刪除等操作進行支持。


配置Row

  • - tableView:heightForRowAtIndexPath:

可以爲指定的行設置高度

- (CGFloat)tableView:(UITableView *)tableView 
heightForRowAtIndexPath:(NSIndexPath *)indexPath;

你可以rowHeight爲所有的cell統一設置高度、相對性能較高。
而一旦實現heightForRowAtIndexPath方法、你就必須爲每一個indexPath設置高度。
返回UITableViewAutomaticDimension則由系統自適應計算。

  • - tableView:estimatedHeightForRowAtIndexPath:

返回指定位置的預估行高

- (CGFloat)tableView:(UITableView *)tableView 
estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath;
  1. 如果沒有預估、可以返回UITableViewAutomaticDimension
  2. 使用此功能可以將某些計算、從加載時移動到滾動時進行。以提高性能。
  • - tableView:indentationLevelForRowAtIndexPath:

返回縮進級別

- (NSInteger)tableView:(UITableView *)tableView 
indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath;

並不知道有什麼地方必須這樣用


  • - tableView:willDisplayCell:forRowAtIndexPath:

某個indexPath的cell將要被繪製(展示)

- (void)tableView:(UITableView *)tableView 
  willDisplayCell:(UITableViewCell *)cell 
forRowAtIndexPath:(NSIndexPath *)indexPath;

由於cellForRow實際上會預創建一些cell、所以cell內部的賦值可以放在這裏、以提升一些性能。
但是最顯著的用途還是對剛展示出來的cell做一些動畫吧。比如從右側一個一個滑入之類。

  • - tableView:shouldSpringLoadRowAtIndexPath:withContext:

cell是否支持iOS11 新特性 Drag and Drop (默認YES)

- (BOOL)tableView:(UITableView *)tableView 
shouldSpringLoadRowAtIndexPath:(NSIndexPath *)indexPath 
      withContext:(id<UISpringLoadedInteractionContext>)context;

擴展按鈕

  • - tableView:editActionsForRowAtIndexPath:

自定義左滑事件

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView 
                  editActionsForRowAtIndexPath:(NSIndexPath *)indexPath;

返回一個由UITableViewRowAction組成的數組。
他們會響應用對應的點擊交互。
如果你不實現這個代理、右滑時將會展示默認按鈕。

  • - tableView:accessoryButtonTappedForRowWithIndexPath:

當cell的擴展視圖被點擊時調用

- (void)tableView:(UITableView *)tableView 
accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath;

這裏的擴展視圖指的是cell.accessoryType的視圖。如下圖所示:


選擇管理

cell被點擊時引起的一系列方法調用

需要注意的是即使cell.selectionStyle = UITableViewCellSelectionStyleNone;使得cell跟隨點擊而改變背景色、以下方法也會被調用。

  • - tableView:willSelectRowAtIndexPath:

將要被選定時觸發

- (NSIndexPath *)tableView:(UITableView *)tableView 
  willSelectRowAtIndexPath:(NSIndexPath *)indexPath;

允許你通過返回一個新的NSIndexPath、來修改將要被選擇的cell。
編輯狀態下不會觸發此方法

  • - tableView:didSelectRowAtIndexPath:

cell被選定時觸發

- (void)tableView:(UITableView *)tableView 
didSelectRowAtIndexPath:(NSIndexPath *)indexPath;

編輯狀態下不會觸發此方法

  • - tableView:willDeselectRowAtIndexPath:

選中狀態被取消時觸發

- (NSIndexPath *)tableView:(UITableView *)tableView 
willDeselectRowAtIndexPath:(NSIndexPath *)indexPath;

如果你返回nil、將不會被取消。允許從定向

  • - tableView:didDeselectRowAtIndexPath:

cell選中被取消時觸發

- (void)tableView:(UITableView *)tableView 
didDeselectRowAtIndexPath:(NSIndexPath *)indexPath;

頁眉和頁腳

//返回頁眉和頁腳
- (nullable UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section; 
- (nullable UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section; 

//返回頁眉和頁腳的高度
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section;
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section;

//頁眉和頁腳將要展示
- (void)tableView:(UITableView *)tableView willDisplayHeaderView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);
- (void)tableView:(UITableView *)tableView willDisplayFooterView:(UIView *)view forSection:(NSInteger)section NS_AVAILABLE_IOS(6_0);

//預估頁眉和頁腳高度
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForHeaderInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForFooterInSection:(NSInteger)section NS_AVAILABLE_IOS(7_0);

以上的方法通過方法名基本都能理解其用處。

這裏需要注意

iOS11之後、系統爲我們設置了預估行高。如果只實現了header高度爲0.1f、而沒有返回具體的view會引起留白的bug。《詳見》


編輯表單

要讓表單支持左滑

你必須實現commitEditingStyle方法、以告訴tableView左滑操作是由價值的

  • - tableView:willBeginEditingRowAtIndexPath:

表單即將進入編輯模式(左滑)

- (void)tableView:(UITableView *)tableView 
willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath;
  • -tableView:didEndEditingRowAtIndexPath:

已經離開編輯模式

- (void)tableView:(UITableView *)tableView 
didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath;

編輯接觸(並不限於取消)觸發、並不會記錄你執行了哪種操作。
所以、你應該在tableView:commitEditingStyle:forRowAtIndexPath:而不是這裏實現相關編輯操作。

  • - tableView:editingStyleForRowAtIndexPath:

決定左滑返回哪種附加視圖

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView 
           editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath;

默認返回UITableViewCellEditingStyleDelete

typedef NS_ENUM(NSInteger, UITableViewCellEditingStyle) {
    UITableViewCellEditingStyleNone,//沒有編輯樣式
    UITableViewCellEditingStyleDelete,//刪除樣式 (左邊是紅色減號)
    UITableViewCellEditingStyleInsert//插入樣式  (左邊是綠色加號)
};
  • - tableView:titleForDeleteConfirmationButtonForRowAtIndexPath:

更改UITableViewCellEditingStyleDelete下的文字

- (NSString *)tableView:(UITableView *)tableView 
titleForDeleteConfirmationButtonForRowAtIndexPath:(NSIndexPath *)indexPath;

setEditing以及左滑時同樣有效。

  • - tableView:shouldIndentWhileEditingRowAtIndexPath:

進入編輯模式時、cell背景是否縮進

- (BOOL)tableView:(UITableView *)tableView 
shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath;

通知委託在編輯模式下是否需要對錶視圖指定行進行縮進,NO爲關閉縮進,這個方法可以用來去掉move時row前面的空白。


重新排序表單

  • tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath:

在移動cell的時候會多次調用

- (NSIndexPath *)tableView:(UITableView *)tableView 
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath 
       toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath;

cell的初始位置以及目標。允許對目標位置重定向。
移動中的留白動畫、以及結果都會受此影響。


移動出可見範圍

cell/sectionHeaderView/sectionFooterView的消失

//cell已經移動出可見範圍
- (void)tableView:(UITableView *)tableView 
didEndDisplayingCell:(UITableViewCell *)cell 
forRowAtIndexPath:(NSIndexPath *)indexPath;

//sectionHeaderView已經移動出可見範圍
- (void)tableView:(UITableView *)tableView 
didEndDisplayingHeaderView:(UIView *)view 
       forSection:(NSInteger)section;

//sectionFooterView已經移動出可見範圍
- (void)tableView:(UITableView *)tableView 
didEndDisplayingFooterView:(UIView *)view 
       forSection:(NSInteger)section;

MENU菜單

如果想讓cell支持menu菜單的呼出、必須將以下三個方法全部實現

  • - tableView:shouldShowMenuForRowAtIndexPath:

長按後是否顯示編輯菜單

- (BOOL)tableView:(UITableView *)tableView 
shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath;
  • - tableView:canPerformAction:forRowAtIndexPath:withSender:

返回該cell支持那種action

- (BOOL)tableView:(UITableView *)tableView 
 canPerformAction:(SEL)action 
forRowAtIndexPath:(NSIndexPath *)indexPath 
       withSender:(id)sender;

這個規則你可以參考iOS文檔補完計劃--UIResponder中關於canPerformAction:withSender:方法的解釋。

  • - tableView:performAction:forRowAtIndexPath:withSender:

讓代理者對menu操作進行響應

- (void)tableView:(UITableView *)tableView 
    performAction:(SEL)action 
forRowAtIndexPath:(NSIndexPath *)indexPath 
       withSender:(id)sender;

高亮管理

高亮權限、高亮、取消高領

//點擊時是否高亮。默認YES
- (BOOL)tableView:(UITableView *)tableView 
shouldHighlightRowAtIndexPath:(NSIndexPath *)indexPath;

//已經高亮
- (void)tableView:(UITableView *)tableView 
didHighlightRowAtIndexPath:(NSIndexPath *)indexPath;


//不再高亮
- (void)tableView:(UITableView *)tableView 
didUnhighlightRowAtIndexPath:(NSIndexPath *)indexPath;

最後

本文主要是自己的學習與總結。如果文內存在紕漏、萬望留言斧正。如果願意補充以及不吝賜教小弟會更加感激。


參考資料

官方文檔-UITableView
iOS UITableView 的 Plain和Grouped樣式的區別
iOS_UITableView 編輯(cell的插入, 刪除, 移動)
ios tableView那些事 (五) 給tableview設置縮進級別
關於UITableView委託方法的功能(by atany)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章