如何修改一次程式碼就可以完成多種型別 cell 的 UITableView 增刪修改
前言
當一個 tableView 中的 cell 型別過多時,我們務必會在 tableView 的各個代理中做這樣那樣的判斷,當需要增加一種 cell,或調換 cell 的順序的時候我們就會在 tableView 的各個代理中進行修改判斷。
使用 ZBCellConfig 可以應對各種變態需求,當增刪、調換 cell 的順序時,只需一鍵配置。
簡介
- ZBCellConfig 物件例項會將 tableView 中 cell 所需的基本資訊儲存下來,然後放到陣列中進行管理;
- 每個 ZBCellConfig 例項與 tableView 中想要顯示的 cell 相對應。(但注意,是"想要顯示的"cell,由於 cell 的重用,實際上 cell 並不會生成那麼多);
- 優點:改變不同型別 cell 的順序、增刪時,極為方便,只需改變用於存放 ZBCellConfig 的陣列即可,** 重點是無需在多個 tableView 代理方法中逐個修改 **。
結構
使用
- 支援 cocoapods 匯入
pod 'ZBCellConfig'
- 直接將檔案拖拽到專案中
#import "ZBCellConfig.h"
知識點
請下載示例專案檢視詳細使用方法及實際中如何使用 GitHub 下載地址。
初、中、高、高 MVVM 內容上是一樣的,區別在於沒一級別知識點遞增。
基本使用
1 . 首先在控制器中宣告存放 ZBCellConfig 例項的二維陣列
/** * 二維陣列 (匹配 tableView 的資料結構,第一層是 section,第二層放 cell) */ @property (nonatomic, strong) NSMutableArray <NSArray <ZBCellConfig *> *> * cellConfigs;
2-1 . 初始化陣列,每一個 ZBCellConfig 為 cell 的基本資訊,改變不同型別 cell 的順序、增刪時,只需在此修改即可,無需在多個 tableView 代理方法中逐個修改(具體檢視 Demo 註釋很清晰)
- (NSMutableArray<NSArray<ZBCellConfig *> *> *)cellConfigs { _cellConfigs = [[NSMutableArray alloc] init]; // cell1 ZBCellConfig *cell1Config = [ZBCellConfig cellConfigWithClass:[LowTableViewCell1 class] showCellInfoMethod:@selector(setModel:)]; [_cellConfigs addObject:@[cell1Config]]; // cell2 ZBCellConfig *cell2Config = [ZBCellConfig cellConfigWithClass:[LowTableViewCell1 class] showCellInfoMethod:@selector(setModel:)]; [_cellConfigs addObject:@[cell2Config]]; // cell3 .... return _cellConfigs; }
2-2 . 增刪只需這樣:
3 . tableView 代理中實現部分
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return self.cellConfigs.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.cellConfigs[section] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// 根據 indexPath 獲取 對應的 cellConfig
ZBCellConfig *cellConfig = self.cellConfigs[indexPath.section][indexPath.row];
// 根據對應的 cellConfig 獲取 cell,並給 cell 賦值 根據模型顯示。
// • dataModels: 這裡由於為示例程式碼不是用真實資料,只起到 執行 cell 的賦值函式。在實際專案中應該傳遞從網路請求的真實資料。
UITableViewCell *cell = [cellConfig cellOfCellConfigWithTableView:tableView dataModels:@[[LowModel new]]];
return cell;
}
cell 自適應高度
1 . tableView 設定如下
/**
* default is 0, which means there is no estimate
* estimatedRowHeight 預設為 0,不估算cell高度
* 賦值不為 0 時候,開啟cell估值配合 layout 約束,進行cell高度自適應
* 也就是說想要自動佈局 cell 高度就給這個 estimatedRowHeight 屬性賦值,值為你所有 cell 的平均高度的一個估值
*/
_heightTableView.estimatedRowHeight = 100;
// iOS8 系統中 rowHeight 的預設值已經設定成了 UITableViewAutomaticDimension
_heightTableView.rowHeight = UITableViewAutomaticDimension;
2 . cell 需採用 AutoLayout 佈局,masory 或 xib 託線的形式皆可,約束規定上左下右還有讓 cell 知道內容的高:
tableView style
- UITableViewStylePlain 和 UITableViewStyleGrouped 區別
- UITableViewStylePlain:sectionView 當 tableView cectionHeader/Footer 會預設高度為 0, 滑動到頂部時 會停留到導航欄底部
- UITableViewStyleGrouped:sectionView 當 tableView cectionHeader/Footer 會預設高度為 10, 滑動到頂部時 不會停留到導航欄底部
- 注意:當需要 為 UITableViewStyleGrouped 時檢視【MediaExample 使用示例】
ZBCellConfig
通過函式 - (void)zb_performSelector:(SEL)aSelector withObjects:(NSArray *)objects
來執行 初始化時配置好的showCellInfoMethod
。
此函式是對 - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
的一個擴充套件,以陣列的形式來傳遞多引數。
函式實現部分:
// 簽名
NSMethodSignature *signature = [[self class] instanceMethodSignatureForSelector:aSelector];
if (signature == nil) {
NSAssert(false, @"LINE=%d ERROR - 找不到 %@ 方法", __LINE__ ,NSStringFromSelector(aSelector));
}
// 包裝
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
// 設定呼叫者
[invocation setTarget:self];
// 設定呼叫的方法 與 NSMethodSignature 簽名的方法一致
[invocation setSelector:aSelector];
// 0為target 1為_cmd 所以從2索引
for (int i = 0; i < (signature.numberOfArguments - 2); i++) {
id dataModel = i < objects.count ? objects[i] : nil;
[invocation setArgument:&dataModel atIndex:i+2];
}
// retain 所有引數,防止釋放
[invocation retainArguments];
[invocation invoke];
總結
把將要展示的幾種 cell 的基本資訊 以 tableView 的資料結構二維陣列的形式存放,儲存基本配置並不會生成多餘的 cell,內部建立採用 tableView 的重用機制。示例 Demo 中註釋詳細,Demo 下載地址。
_ If I have no knife,I can't protect you.If I had a sword,I can't hold you.
如果我沒有刀,我就不能保護你。如果我有刀,我就不能擁抱你。
————《剪刀手愛德華》_