iOS多種類型的cell處理方案

在項(xiàng)目開發(fā)中UITableView和UICollectionView應(yīng)該是最長用的控件了吧巴席,而這兩種控件的核心是cell的處理和展示。隨著App的發(fā)展和需求的不斷累加祟牲,頁面是單一cell的情況越來越少狂魔,更多的是各種復(fù)雜cell的組合椎咧。常見的比如App的首頁


app首頁示例圖

那么像這種頁面我們是如何處理cell的呢侠讯?

1.最常見的也是很多人會(huì)不經(jīng)思考的挖藏,直接根據(jù)indexPath一一對(duì)應(yīng),寫出下面的代碼:

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

? ? if(indexPath.section==0) {

? ? }

}

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

? ? [tableViewdeselectRowAtIndexPath:indexPath animated:YES];

? ? if(indexPath.section==0) {

? ?}
}

雖然這種在開發(fā)階段很容易厢漩,但是在后期的二次開發(fā)和維護(hù)上改一個(gè)地方tableview的delegate和datasource的方法都需要改膜眠,成本很高。而且cellForRowAtIndexPath的方法里面是清一色的if-else溜嗜,然后是做了各種各樣的事情宵膨,很容易造成代碼的臃腫,動(dòng)不動(dòng)就是幾十行或者幾百行代碼炸宵,不利于閱讀和重用辟躏。

這種方案的缺點(diǎn)有以下幾點(diǎn):

1.一般情況下項(xiàng)目中不建議出現(xiàn)0、1等具體的數(shù)字土全,因?yàn)樗吮硎疚恢弥馍铀觯翢o其他意義。

2.容易出錯(cuò)裹匙,在cell代理方法瑞凑,高度代理方法,點(diǎn)擊代理方法里面要保持一致概页,容易出錯(cuò)籽御。

3.不方便修改,如果要修改兩個(gè)cell的順序或者添加修改惰匙,要修改好幾個(gè)地方技掏,改動(dòng)太大。

2.根據(jù)model來對(duì)應(yīng)cell项鬼,cell面向model開發(fā)

前面提到了不因該出現(xiàn)indexPath等具體的位置數(shù)字零截,對(duì)于一個(gè)tableview,位置數(shù)字肯定是有的秃臣,我們要消除數(shù)字涧衙,那就得找到相應(yīng)的數(shù)據(jù)來代替它。這里奥此,主要的場景一般都是一個(gè)類型的數(shù)據(jù)(model)對(duì)應(yīng)一種類型的cell弧哎,所以類型是固定的,所以我們用一個(gè)枚舉來定義所有類型的cell

typedefNS_ENUM(NSInteger, HomeCellType) {

?HomeCellTypeOne =0,

?HomeCellTypeTwo?

?HomeCellTypeThree,?

?HomeCellTypeFourl,?

?};

然后在cellForRow方法稚虎,根據(jù)model類型加載對(duì)應(yīng)的cell撤嫩,例如:

? ?id model = self.viewModel.dataArray[indexPath.row];

switch([self?getHomeCellType] ){

? caseHomeCellTypeOne:

?HomeCellOne?*cell = [collectionView dequeueReusableCellWithReuseIdentifier:[HomeCellOne cellIdentifier] forIndexPath:indexPath];

? ?breke;

caseHomeCellTypeOne:

?HomeCellTwo *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[HomeCellTwo?cellIdentifier] forIndexPath:indexPath];

? ?breke;

? ?....

}

?- (HomeCellType)getHomeCellType:(id)model {

? ? ? ? HomeCellType type = HomeCellTypeOne;

? ? ? ? if([model isKindOfClass:[HomeCellTypeOneModel class]]) {

? ? ? ? ? ? type = HomeCellTypeOne;

? ? ? ? }else if([model isKindOfClass:[HomeCellTypeTwoModel class]]) {

? ? ? ? ? ? type = HomeCellTypeTwo;

? ? ? ? }else if(){

? ? ? ? }

? ? ? ...

}

這樣看到了cellType或者model就知道如何去處理相應(yīng)的cell了,清晰易理解蠢终。而且如果想復(fù)用序攘、刪除茴她、添加、改動(dòng)順序程奠,只需要改動(dòng)數(shù)據(jù)源即可丈牢,其他不需要?jiǎng)樱膭?dòng)量很小瞄沙。但是這樣寫的還不是很好己沛,cell和datasource的cellForRowAtIndexPath耦合的還有點(diǎn)嚴(yán)重。那如果其他的地方只是用到了部分cell類型距境,我們還需要把上面的代碼再copy一份申尼?或者說我想讓cell根據(jù)model去自動(dòng)選擇cell類型,而不是import各種cell垫桂。頭文件师幕,在cellForRowAtIndexPath方法里面判斷,不依賴具體的cell呢诬滩?

那么我的面向協(xié)議開發(fā)的設(shè)計(jì)模式就上場了们衙。就是讓model繼承一個(gè)協(xié)議,該協(xié)議實(shí)現(xiàn)了cell的一些方法碱呼,例如cell的復(fù)用標(biāo)示蒙挑、cell的類型、cell的高度愚臀、cell的點(diǎn)擊事件等忆蚀。

改進(jìn)版

1.定義協(xié)議接口

@protocol ModelConfigProtocol

@optional

/**

獲取 cell 的復(fù)用標(biāo)識(shí)

@return 復(fù)用標(biāo)識(shí)

*/

- (nullableNSString*)cellReuseIdentifier;

/**

獲取 cell 的類型

@return cell 的類型

*/

- (cellType)cellType;

/**

獲取 cell 的高度

@param indexPath indexPath

@return 高度

*/

- (CGFloat)cellHeightWithindexPath:(NSIndexPath*)indexPath;

/**

cell 點(diǎn)擊

@param indexPath indexPath

@param other 其它對(duì)象

*/

- (void)cellDidSelectRowAtIndexPath:(NSIndexPath*)indexPath other:(_Nullable id)other;

2.然后實(shí)現(xiàn)實(shí)現(xiàn)該協(xié)議接口。定義一個(gè)抽象類的model遵守該協(xié)議實(shí)現(xiàn)協(xié)議

@interface BaseModel : NSObject<ModelConfigProtocol>

@end

@implementation BaseModel

- (cellType)cellType{

? ? return0;

}

- (NSString*)cellReuseIdentifier{

? ? return@"";

}

- (CGFloat)cellHeightWithindexPath:(NSIndexPath*)indexPath{

? ? return0.0;

}

- (void)cellDidSelectRowAtIndexPath:(NSIndexPath*)indexPath other:(_Nullable id)other{

? ? return;

}

@end

3.具體的model繼承自BaseModel姑裂,然后子類model具體實(shí)現(xiàn)ModelConfigProtocol的協(xié)議方法

4.定義的一個(gè)抽象類的cell馋袜,開放賦值的接口

@interfaceBaseCell : UITableViewCell

@property (nonatomic,strong) id<ModelConfigProtocol> model;

@end

@implementation BaseCell

- (void)setModel:(id)model{

}

@end

5.具體的cell繼承自BaseCell,然后子類cell具體實(shí)現(xiàn)setModel方法

6.TableView代理里數(shù)據(jù)返回

#pragma mark ---- UITableViewDelegate ----

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

{

id<ModelConfigProtocol>?model =self.listArray[indexPath.row];

return [model cellHeightWithindexPath:indexPath];

}

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

{

[tableView deselectRowAtIndexPath:indexPath animated:YES];

id<ModelConfigProtocol> mdoel =self.viewModel.dataArray[indexPath.row];

[model cellDidSelectRowAtIndexPath:indexPath other:nil];

}

#pragma mark ---- UITableViewDataSource ----

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

{

return1;

}

- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section{

return self.viewModel.dataArray.count;

}

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

{

id<ModelConfigProtocol>?model =self.viewModel.dataArray[indexPath.row];

? ? BaseCell *cell = [tableView dequeueReusableCellWithIdentifier:[model cellReuseIdentifier]];

? ? cell.cellConfig = model;

returncell;

}

一般的一種類型的cell對(duì)應(yīng)一種model舶斧,如果你想一種model對(duì)應(yīng)多種cell欣鳖,例如微信消息,有文本消息茴厉、圖片消息泽台、語音消息、紅包消息矾缓、視頻消息等怀酷。你可以在具體model的cellType再做一層判斷。最厲害的地方在于可以和MVVM嗜闻、適配器無縫對(duì)接蜕依,寫一個(gè)BaseViewController實(shí)現(xiàn)這些,然后其他ViewController繼承它,只需改變數(shù)據(jù)源样眠,即可實(shí)現(xiàn)用最少的代碼實(shí)現(xiàn)復(fù)雜的頁面展示友瘤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市檐束,隨后出現(xiàn)的幾起案子辫秧,更是在濱河造成了極大的恐慌,老刑警劉巖厢塘,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異肌幽,居然都是意外死亡晚碾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門喂急,熙熙樓的掌柜王于貴愁眉苦臉地迎上來格嘁,“玉大人,你說我怎么就攤上這事廊移「獠荆” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵狡孔,是天一觀的道長懂诗。 經(jīng)常有香客問我,道長苗膝,這世上最難降的妖魔是什么殃恒? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮辱揭,結(jié)果婚禮上离唐,老公的妹妹穿的比我還像新娘。我一直安慰自己问窃,他們只是感情好亥鬓,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著域庇,像睡著了一般嵌戈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上听皿,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天咕别,我揣著相機(jī)與錄音,去河邊找鬼写穴。 笑死惰拱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播偿短,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼欣孤,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了昔逗?” 一聲冷哼從身側(cè)響起降传,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勾怒,沒想到半個(gè)月后婆排,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笔链,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年段只,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鉴扫。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡赞枕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坪创,到底是詐尸還是另有隱情炕婶,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布莱预,位于F島的核電站柠掂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏依沮。R本人自食惡果不足惜陪踩,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悉抵。 院中可真熱鬧肩狂,春花似錦、人聲如沸姥饰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽列粪。三九已至审磁,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岂座,已是汗流浹背态蒂。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留费什,地道東北人钾恢。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親瘩蚪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子泉懦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容