在日常的開發(fā)中,有時(shí)會(huì)遇到內(nèi)容塊比較多拗馒,且又可變的界面:
這個(gè)界面中有些內(nèi)容塊是固定出現(xiàn)的,比如最上面的商品詳情圖片溯街、商品名稱诱桂、價(jià)格等。而有些內(nèi)容塊則是不一定出現(xiàn)的呈昔,比如促銷(顯然不是每個(gè)商品都有促銷)挥等、已選規(guī)格(有的商品沒有規(guī)格)、店鋪信息(有的商品屬于自營韩肝,就沒有店鋪)等触菜。還有些內(nèi)容要根據(jù)情況進(jìn)行變化,比如評論哀峻,這里最多列出4條評論涡相,如果沒有評論,則顯示“暫無評論”且不顯示“查看所有評論”按鈕剩蟀。
對于這樣的界面催蝗,相信很多人第一感覺會(huì)用TableView來做,因?yàn)橹虚g要列出評論內(nèi)容育特,這個(gè)用TableView的cell來填充比較合適丙号。但如何處理評論內(nèi)容之外的其他內(nèi)容呢?我之前的做法是缰冤,評論內(nèi)容之上的用HeaderView做犬缨,下面的用FooterView做,雖然最終實(shí)現(xiàn)了功能棉浸,但做起來十分麻煩怀薛。布局我是用Auto Layout來做的,由于Auto Layout本身的特點(diǎn)迷郑,這種做法在控制內(nèi)容塊View的顯示與否枝恋,需要比較多的操作:
- View的高度約束設(shè)置為0
- 最好還要把子View全部移除,否則嗡害,子View里的約束可能會(huì)因?yàn)閂iew高度約束設(shè)置為0而出現(xiàn)約束沖突
- 如果View本身有距離前面View的間距約束焚碌,也需要將間距約束設(shè)置為0
- View的hidden設(shè)置為yes,以減少視圖繪制
此外霸妹,還有一個(gè)麻煩的問題十电。界面剛進(jìn)來的時(shí)候,是需要請求網(wǎng)絡(luò)數(shù)據(jù),這時(shí)界面就要顯示成一個(gè)初始狀態(tài)摆出,而顯然初始狀態(tài)有些內(nèi)容塊是不應(yīng)該顯示的朗徊,比如促銷,只有完成了數(shù)據(jù)請求偎漫,才能知道是否有促銷爷恳,有的話才顯示促銷內(nèi)容;比如評論象踊,初始時(shí)應(yīng)該顯示成“暫無評論”温亲,數(shù)據(jù)請求完成后,才顯示相應(yīng)的內(nèi)容杯矩。這樣栈虚,我們需要處理初始進(jìn)入和數(shù)據(jù)請求完成兩種狀態(tài)下各個(gè)內(nèi)容塊的顯示,十分復(fù)雜繁瑣史隆。
總結(jié)來說魂务,用TableView的 HeaderView + 評論內(nèi)容cell + FooterView + Auto Layout 的方式會(huì)帶來如下問題:
- 約束在View與View之間是有依賴關(guān)系的,對View的顯示與否泌射,需要比較多的操作
- 需要處理初始進(jìn)入和數(shù)據(jù)請求完成兩種狀態(tài)的界面展示粘姜,使代碼更加復(fù)雜繁瑣
- 需要額外計(jì)算相應(yīng)內(nèi)容的高度,以更新HeaderView熔酷、FooterView的高度
可見孤紧,這種方式并不是理想的解決方案【苊兀可能有人會(huì)說号显,那不要用Auto Layout,直接操作frame來布局就好躺酒,這樣或許能減少一些麻煩押蚤,但總體上并沒有減少復(fù)雜度。也有人說羹应,直接用ScrollView來做活喊,這樣的話,所有的內(nèi)容包括評論內(nèi)容的cell量愧,都得自己手動(dòng)拼接,可以想象這種做法也是比較麻煩的帅矗。所以偎肃,我們得另辟蹊徑,使用其他方法來達(dá)到目的浑此。下面就為大家介紹一種比較簡便的做法累颂,這種做法也是一個(gè)前同事分享給我的,我就借花獻(xiàn)佛,分享給大家紊馏。
我們還是用TableView來做這個(gè)界面料饥,和之前不同的是,我們把每一個(gè)可變內(nèi)容塊做成一個(gè)獨(dú)立的cell朱监,cell的粒度可以自行控制岸啡,比如可以用一個(gè)cell囊括商品圖片、標(biāo)題赫编、副標(biāo)題巡蘸、價(jià)格,也可以拆得更細(xì)擂送,圖片悦荒、標(biāo)題、副標(biāo)題嘹吨、價(jià)格都各自對應(yīng)一個(gè)cell搬味。這里我們選擇后者,因?yàn)閳D片內(nèi)容塊蟀拷,我們需要按屏幕寬度等比例拉伸碰纬;標(biāo)題、副標(biāo)題的文字內(nèi)容可能是一行匹厘,也可能是兩行嘀趟,高度可變,用單獨(dú)的cell來控制會(huì)更簡單明了愈诚,也更加靈活她按。
下面先定義好各種類型的cell:
//基礎(chǔ)cell,這里為了演示簡便炕柔,定義這個(gè)cell酌泰,其他cell繼承自這個(gè)cell
@interface MultipleVariantBasicTableViewCell : UITableViewCell
@property (nonatomic, weak) UILabel *titleTextLabel;
@end
//滾動(dòng)圖片
@interface CycleImagesTableViewCell : MultipleVariantBasicTableViewCell
@end
//正標(biāo)題
@interface MainTitleTableViewCell : MultipleVariantBasicTableViewCell
@end
//副標(biāo)題
@interface SubTitleTableViewCell : MultipleVariantBasicTableViewCell
@end
//價(jià)格
@interface PriceTableViewCell : MultipleVariantBasicTableViewCell
@end
// ...其他內(nèi)容塊的cell聲明
// 各種內(nèi)容塊cell的實(shí)現(xiàn),這里為了演示簡便匕累,cell中就只放了一個(gè)Label
@implementation MultipleVariantBasicTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
label.numberOfLines = 0;
[self.contentView addSubview:label];
self.titleTextLabel = label;
}
return self;
}
@end
@implementation CycleImagesTableViewCell
@end
@implementation MainTitleTableViewCell
@end
// ...其他內(nèi)容塊的cell實(shí)現(xiàn)
// 評論內(nèi)容cell使用Auto Layout陵刹,配合iOS 8 TableView的自動(dòng)算高,實(shí)現(xiàn)內(nèi)容自適應(yīng)
@implementation CommentContentTableViewCell
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.titleTextLabel.translatesAutoresizingMaskIntoConstraints = NO;
self.titleTextLabel.preferredMaxLayoutWidth = [UIScreen mainScreen].bounds.size.width - 8;
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:4.0f];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-4.0f];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:4.0f];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.titleTextLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-4.0f];
[self.contentView addConstraints:@[leftConstraint, rightConstraint, topConstraint, bottomConstraint]];
}
return self;
}
@end
接下來就是重點(diǎn)欢嘿,就是如何來控制顯示哪些cell及cell顯示的數(shù)量衰琐。這一步如果處理不好,也會(huì)使開發(fā)變得復(fù)雜炼蹦。如下面的方式:
// 加載完數(shù)據(jù)
self.cellCount = 0;
if (存在促銷) {
self.cellCount++;
}
if (存在規(guī)格) {
self.cellCount++;
}
......
如果以這種方式來記錄cell的數(shù)量羡宙,那么后續(xù)cell的展示、點(diǎn)擊判斷等都會(huì)很麻煩掐隐。這里我們采用的方式是狗热,使用單獨(dú)的類(作為一種數(shù)據(jù)結(jié)構(gòu))來保存所要展示的cell信息钞馁。
// SKRow.h
@interface SKRow : NSObject
@property (nonatomic, copy) NSString *cellIdentifier;
@property (nonatomic, strong) id data;
@property (nonatomic, assign) float rowHeight;
- (instancetype)initWithCellIdentifier:(NSString *)cellIdentifier
data:(id)data
rowHeight:(float)rowHeight;
@end
// SKRow.m
#import "SKRow.h"
@implementation SKRow
- (instancetype)initWithCellIdentifier:(NSString *)cellIdentifier data:(id)data rowHeight:(float)rowHeight {
if (self = [super init]) {
self.cellIdentifier = cellIdentifier;
self.data = data;
self.rowHeight = rowHeight;
}
return self;
}
@end
SKRow用來存儲(chǔ)每個(gè)cell所需的信息,包括重用標(biāo)識(shí)匿刮、數(shù)據(jù)項(xiàng)僧凰、高度。接下來熟丸,我們就開始拼接cell信息训措。
@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) NSMutableArray<NSArray<SKRow *> *> *tableSections;
@end
self.tableSections = [NSMutableArray array];
/* 初始加載數(shù)據(jù)
* 初始化時(shí),只顯示滾動(dòng)圖片虑啤、價(jià)格隙弛、評論頭、無評論
*/
// 滾動(dòng)圖片(寬高保持比例)
SKRow *cycleImagesRow = [[SKRow alloc] initWithCellIdentifier:@"CycleImagesCellIdentifier" data:@[@"滾動(dòng)圖片地址"] rowHeight:120*[UIScreen mainScreen].bounds.size.width / 320.f];
// 價(jià)格
SKRow *priceRow = [[SKRow alloc] initWithCellIdentifier:@"PriceCellIdentifier" data:@"0" rowHeight:44];
[self.tableSections addObject:@[cycleImagesRow, priceRow]];
// 評論頭
SKRow *commentSummaryRow = [[SKRow alloc] initWithCellIdentifier:@"CommentSummaryCellIdentifier" data:@{@"title":@"商品評價(jià)", @"count":@"0"} rowHeight:44];
// 無評論
SKRow *noCommentRow = [[SKRow alloc] initWithCellIdentifier:@"NoCommentCellIdentifier" data:@"暫無評論" rowHeight:44];
[self.tableSections addObject:@[commentSummaryRow, noCommentRow]];
以上是初始狀態(tài)時(shí)要顯示的cell狞山,我們在ViewController中聲明一個(gè)數(shù)組全闷,用來存儲(chǔ)TableView各個(gè)section要顯示的cell信息。這里我們將cell分成不同的section萍启,實(shí)際中总珠,要不要分,分成幾個(gè)section都可以自行決定勘纯。初始狀態(tài)我們有兩個(gè)section局服,第一個(gè)section用于顯示基本信息,第二個(gè)section用于顯示評論信息驳遵,這樣就完成了cell信息的拼接淫奔,接下來就是顯示:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// 這里可以通過判斷cellIdentifier來區(qū)分處理各種不同的cell,cell所需的數(shù)據(jù)從row.data上獲取
SKRow *row = self.tableSections[indexPath.section][indexPath.row];
if ([row.cellIdentifier isEqualToString:@"CycleImagesCellIdentifier"]) {
CycleImagesTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
NSArray<NSString *> *urlStringArray = row.data;
cell.titleTextLabel.text = [urlStringArray componentsJoinedByString:@"\n"];
return cell;
} else if ([row.cellIdentifier isEqualToString:@"MainTitleCellIdentifier"]) {
MainTitleTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
cell.titleTextLabel.text = row.data;
return cell;
} else if ([row.cellIdentifier isEqualToString:@"PriceCellIdentifier"]) {
PriceTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
cell.titleTextLabel.text = [NSString stringWithFormat:@"¥%@", row.data];
return cell;
} else if ([row.cellIdentifier isEqualToString:@"SalePromotionCellIdentifier"]) {
SalePromotionTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
NSArray<NSString *> *salePromotionStringArray = row.data;
cell.titleTextLabel.text = [salePromotionStringArray componentsJoinedByString:@"\n"];
return cell;
} else if ([row.cellIdentifier isEqualToString:@"SpecificationCellIdentifier"]) {
SpecificationTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
cell.titleTextLabel.text = [NSString stringWithFormat:@"已選:%@", row.data];
return cell;
} else if ([row.cellIdentifier isEqualToString:@"CommentSummaryCellIdentifier"]) {
CommentSummaryTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
NSDictionary *commentSummary = row.data;
cell.titleTextLabel.text = [NSString stringWithFormat:@"%@(%@)", commentSummary[@"title"], commentSummary[@"count"]];
return cell;
} else if ([row.cellIdentifier isEqualToString:@"CommentContentCellIdentifier"]) {
CommentContentTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
cell.titleTextLabel.text = row.data;
return cell;
} else if ([row.cellIdentifier isEqualToString:@"AllCommentCellIdentifier"]) {
AllCommentTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
cell.titleTextLabel.text = row.data;
return cell;
} else if ([row.cellIdentifier isEqualToString:@"NoCommentCellIdentifier"]) {
NoCommentTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:row.cellIdentifier forIndexPath:indexPath];
cell.titleTextLabel.text = row.data;
return cell;
}
return nil;
}
上面的代碼進(jìn)行了刪減堤结,沒有處理所有類型唆迁。雖然稍嫌冗長,但是邏輯非常簡單竞穷,就是獲取cell信息唐责,根據(jù)重用標(biāo)識(shí)來區(qū)分不同類型的內(nèi)容塊,將數(shù)據(jù)處理后放到cell中展示瘾带。
例如鼠哥,對于商品圖片,因?yàn)槭菨L動(dòng)圖片看政,滾動(dòng)圖片可以有多張朴恳,前面我們傳入的數(shù)據(jù)就是數(shù)組data:@[@"滾動(dòng)圖片地址"]
。后面獲取到數(shù)據(jù)后允蚣,cell.titleTextLabel.text = [urlStringArray componentsJoinedByString:@"\n"];
于颖,出于演示,商品圖片cell我們只放了一個(gè)Label厉萝,所以只是簡單的將地址信息分行顯示出來。在實(shí)際的開發(fā)中,可以放入一個(gè)圖片滾動(dòng)顯示控件谴垫,并將圖片地址的數(shù)組數(shù)據(jù)傳給控件展示章母。
其他類型的cell處理也是大同小異,出于演示的原因翩剪,都只是簡單的數(shù)據(jù)處理展示乳怎。當(dāng)然,別忘了前弯,設(shè)置一下TableView相關(guān)的dataSource和delegate:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
SKRow *row = self.tableSections[indexPath.section][indexPath.row];
return row.rowHeight;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.tableSections.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.tableSections[section].count;
}
這樣我們就完成了初始狀態(tài)時(shí)界面的展示:
完成了cell的顯示處理蚪缀,接下來我們來模擬一下網(wǎng)絡(luò)請求數(shù)據(jù)后,界面如何顯示所需的cell:
self.tableSections = [NSMutableArray array];
NSMutableArray<SKRow *> *section1 = [NSMutableArray array];
// 滾動(dòng)圖片(寬高保持比例)
SKRow *cycleImagesRow = [[SKRow alloc] initWithCellIdentifier:@"CycleImagesCellIdentifier" data:@[@"滾動(dòng)圖片地址1", @"滾動(dòng)圖片地址2", @"滾動(dòng)圖片地址3"] rowHeight:120*[UIScreen mainScreen].bounds.size.width / 320.f];
// 主標(biāo)題
SKRow *mainTitleRow = [[SKRow alloc] initWithCellIdentifier:@"MainTitleCellIdentifier" data:@"商品名稱" rowHeight:44];
// 副標(biāo)題
SKRow *subTitleRow = [[SKRow alloc] initWithCellIdentifier:@"SubTitleCellIdentifier" data:@"節(jié)日促銷恕出,快來買啊" rowHeight:44];
// 價(jià)格
SKRow *priceRow = [[SKRow alloc] initWithCellIdentifier:@"PriceCellIdentifier" data:@(arc4random()) rowHeight:44];
[section1 addObjectsFromArray:@[cycleImagesRow, mainTitleRow, subTitleRow, priceRow]];
// 促銷(隨機(jī)出現(xiàn))
if (arc4random() % 2 == 0) {
SKRow *salePromotionRow = [[SKRow alloc] initWithCellIdentifier:@"SalePromotionCellIdentifier" data:@[@"促銷信息1", @"促銷信息2", @"促銷信息3"] rowHeight:44];
[section1 addObject:salePromotionRow];
}
[self.tableSections addObject:section1];
NSMutableArray<SKRow *> *section2 = [NSMutableArray array];
// 規(guī)格(隨機(jī)出現(xiàn))
if (arc4random() % 2 == 0) {
SKRow *specificationRow = [[SKRow alloc] initWithCellIdentifier:@"SpecificationCellIdentifier" data:@"銀色询枚,13.3英寸" rowHeight:44];
[section2 addObject:specificationRow];
}
if (section2.count > 0) {
[self.tableSections addObject:section2];
}
NSMutableArray<SKRow *> *section3 = [NSMutableArray array];
NSArray<NSString *> *commentArray = [NSMutableArray array];
// 評論內(nèi)容數(shù)據(jù)(隨機(jī)出現(xiàn))
if (arc4random() % 2 == 0) {
commentArray = @[@"評論內(nèi)容1", @"評論內(nèi)容2", @"2016年6月,蘋果系統(tǒng)iOS 10正式亮相浙巫,蘋果為iOS 10帶來了十大項(xiàng)更新金蜀。2016年6月13日,蘋果開發(fā)者大會(huì)WWDC在舊金山召開的畴,會(huì)議宣布iOS 10的測試版在2016年夏天推出渊抄,正式版將在秋季發(fā)布。2016年9月7日丧裁,蘋果發(fā)布iOS 10护桦。iOS10正式版于9月13日(北京時(shí)間9月14日凌晨一點(diǎn))全面推送。", @"評論內(nèi)容4"];
}
// 評論頭
SKRow *commentSummaryRow = [[SKRow alloc] initWithCellIdentifier:@"CommentSummaryCellIdentifier" data:@{@"title":@"商品評價(jià)", @"count":@(commentArray.count)} rowHeight:44];
[section3 addObject:commentSummaryRow];
if (commentArray.count > 0) {
for (NSString *commentString in commentArray) {
// 評論內(nèi)容需要自適應(yīng)高度煎娇,高度值指定為UITableViewAutomaticDimension
SKRow *commentContentRow = [[SKRow alloc] initWithCellIdentifier:@"CommentContentCellIdentifier" data:commentString rowHeight:UITableViewAutomaticDimension];
[section3 addObject:commentContentRow];
}
// 查看所有評論
SKRow *allCommentRow = [[SKRow alloc] initWithCellIdentifier:@"AllCommentCellIdentifier" data:@"查看所有評論" rowHeight:44];
[section3 addObject:allCommentRow];
} else {
// 無評論
SKRow *noCommentRow = [[SKRow alloc] initWithCellIdentifier:@"NoCommentCellIdentifier" data:@"暫無評論" rowHeight:44];
[section3 addObject:noCommentRow];
}
[self.tableSections addObject:section3];
[self.tableView reloadData];
上面的代碼同樣比較冗長二庵,但邏輯也同樣十分簡單。按顯示順序拼湊cell數(shù)據(jù)逊桦,有些不一定顯示的內(nèi)容塊眨猎,如促銷,則隨機(jī)判斷强经,如果顯示睡陪,將數(shù)據(jù)加入到section數(shù)組中[section1 addObject:salePromotionRow];
。其他類型的cell也是類似的匿情,不再贅述兰迫。要注意的是,評論內(nèi)容的文本可能有多行炬称,我們將它的cell高設(shè)置為UITableViewAutomaticDimension:
[[SKRow alloc] initWithCellIdentifier:@"CommentContentCellIdentifier" data:commentString rowHeight:UITableViewAutomaticDimension];
由于評論內(nèi)容cell我們使用了Auto Layout汁果,這樣就可以利用iOS 8 TableView的新特性,自動(dòng)計(jì)算cell的高度玲躯。拼接完數(shù)據(jù)后据德,只要調(diào)用[self.tableView reloadData];
讓TableView重新加載即可鳄乏。
好了,這樣就大功告成:
使用上述方式制作這種內(nèi)容塊可變的界面雖然寫起來較為啰嗦棘利,但有如下優(yōu)點(diǎn):
- 邏輯清晰簡單橱野,易于理解。視圖間不存在像先前HeaderView + Auto Layout + FooterView那種麻煩的約束處理善玫,內(nèi)容塊的顯示與否處理非常簡便水援。
- 性能比較好。有些cell可以復(fù)用茅郎,減少開銷蜗元。并且只加載需要顯示的View,如果是之前的做法系冗,或者用scrollView來做奕扣,雖然最終也是只顯示需要的View,但不需要顯示的View還是要加載進(jìn)來毕谴,有性能損耗成畦。
- 易于靜態(tài)調(diào)整。如果產(chǎn)品經(jīng)理要求調(diào)換內(nèi)容塊的顯示順序涝开,只要移動(dòng)下拼湊cell數(shù)據(jù)的代碼順序即可循帐。如果是去除某個(gè)內(nèi)容塊,代碼上的調(diào)整也不復(fù)雜舀武。
- 易于動(dòng)態(tài)調(diào)整內(nèi)容塊的顯示順序拄养。所謂的動(dòng)態(tài)調(diào)整,是指界面要根據(jù)接口返回的數(shù)據(jù)银舱,來決定哪些內(nèi)容塊顯示在前面瘪匿,哪些顯示的后面。比如接口返回type=0時(shí)寻馏,價(jià)格項(xiàng)顯示在商品名稱之上棋弥,而type=1時(shí),價(jià)格項(xiàng)顯示在商品子標(biāo)題之下诚欠。
- 易于處理相似但又不同的界面顽染。比如商品有好幾種不同的類型,有特惠專區(qū)轰绵,有免費(fèi)專區(qū)的粉寞。免費(fèi)專區(qū)的商品詳情在價(jià)格內(nèi)容塊上要顯示不一樣的內(nèi)容。這時(shí)左腔,就可以多做一種類型的cell唧垦,根據(jù)接口返回type進(jìn)行判斷,如果是免費(fèi)專區(qū)則選取免費(fèi)專區(qū)的cell來顯示液样。用之前HeaderView + Auto Layout的做法振亮,就要費(fèi)神地去調(diào)整約束巧还,事倍功半。
- 易于擴(kuò)展增加新的內(nèi)容塊坊秸。要增加新的內(nèi)容塊狞悲,只需創(chuàng)建新的cell,在數(shù)據(jù)拼接時(shí)妇斤,增加拼接新cell類型的數(shù)據(jù)代碼,同樣在顯示的地方增加顯示新cell類型的代碼即可丹拯,幾乎不需要修改原有的邏輯站超。
最后,附上Demo工程代碼乖酬。注意死相,這個(gè)工程是用XCode 8創(chuàng)建的,低版本的XCode可能運(yùn)行會(huì)有問題(XCode 8的storyboard默認(rèn)好像不兼容老版本)咬像,示例是基于iOS 8算撮,如果要兼容老版本,請自行修改(主要是涉及cell自動(dòng)算高的部分)县昂。
后記
寫這篇文章之初肮柜,只是作為一個(gè)note,想著有哪個(gè)做iOS的朋友遇到類似的問題倒彰,可以給他做個(gè)參考审洞。沒想到,竟引來不少關(guān)注待讳,還被推上公眾號(hào)芒澜,收到不少評論,自己也因此打了一些“口水仗”创淡。
從中痴晦,我也意識(shí)到我少強(qiáng)調(diào)了一件“顯而易見”的事件。我想說琳彩,我的方法并不適用所有情況誊酌,也不是要解決所有的問題。那些持批評觀點(diǎn)的汁针,大多是面臨的問題需求不同所致术辐。就好比我的方法是一把切水果的刀,而你要拿它去剁骨頭施无,那當(dāng)然是不行的辉词,它本來就不是用來剁骨頭的。
當(dāng)然猾骡,很慶幸的是瑞躺,從這些討論批評中敷搪,我也發(fā)現(xiàn)這種方法的一些不足,也有不少有益的收獲幢哨。
不足之處在于:
-
不大適用于交互比較多的界面赡勘。如:點(diǎn)擊某個(gè)按鈕顯示/隱藏某個(gè)數(shù)據(jù)項(xiàng)、填寫表單項(xiàng)等
交互比較多的界面
像這個(gè)界面捞镰,選了優(yōu)惠券后闸与,要更新顯示優(yōu)惠信息,更新對應(yīng)的應(yīng)付款岸售,用這種方法就不方便了
- 多個(gè)接口獲取數(shù)據(jù)并依次展示內(nèi)容項(xiàng)践樱。比如基本信息一個(gè)接口、促銷信息一個(gè)接口凸丸、評論信息一個(gè)接口拷邢,請求到基本信息數(shù)據(jù)就要展示基本信息,請求到促銷數(shù)據(jù)就要展示促銷信息屎慢,以此類推瞭稼,那么數(shù)據(jù)拼接會(huì)比較麻煩
收獲在于,因此認(rèn)識(shí)了@sun6boys腻惠,多了一個(gè)朋友环肘,可謂是不打不相識(shí)。雖然他在文章的評論中并沒有詳細(xì)展示他的方法集灌,但在私下的討論中廷臼,我已經(jīng)窺探到了他的方法全貌。他對我方法不足的指責(zé)是有道理的绝页,他的方法在數(shù)據(jù)的處理上比我規(guī)整荠商,我的方法顯得原始粗暴。對于有交互的界面及從多個(gè)接口獲取數(shù)據(jù)依次展示的處理上续誉,也要更加容易莱没,整體的思路實(shí)現(xiàn)也非常簡潔,可以看作是我這種方法的升級改進(jìn)版酷鸦。更難能可貴的是饰躲,他為此專門寫了一個(gè)demo放到了github上:https://github.com/sun6boys/CRVisibleCellsDemo,大家可以學(xué)習(xí)參考臼隔。
同樣嘹裂,也有其他的解決方法,比如完全用scrollview實(shí)現(xiàn)的:《復(fù)雜界面開發(fā)之所思》摔握。我并不贊同用scrollview來做這種界面寄狼,原因在那篇文章也多有評論,但不管如何,多參考下其他的方法也是有益處的泊愧,至于如何取舍伊磺,就看各位的選擇了。
其實(shí)不論用什么方法删咱,都是一種權(quán)衡屑埋,需要根據(jù)自身的情境去考慮。比如你所面臨的需求痰滋,是純展示型的界面摘能,還是交互比較多的界面。比如團(tuán)隊(duì)的開發(fā)習(xí)慣敲街,我的團(tuán)隊(duì)比較不習(xí)慣用scrollview徊哑,自然解決方法就會(huì)向tableview靠。比如團(tuán)隊(duì)技能聪富、學(xué)習(xí)成本,有的方法對約束的使用要求較高著蟹,這就是一種技能要求墩蔓、一種門檻,會(huì)對團(tuán)隊(duì)開發(fā)和新人融入產(chǎn)生影響萧豆。有人說我的方法偏傻瓜式奸披,這是對的,因?yàn)檫@也是我所追求的涮雷。傻瓜式就意味著容易上手阵面,團(tuán)隊(duì)成員可以很容易使用這個(gè)方法,不管是接手別人的代碼洪鸭,還是有新人進(jìn)入團(tuán)隊(duì)样刷,做這一塊的東西,都不會(huì)多高的門檻览爵。并且這個(gè)方法也已經(jīng)足夠解決目前的問題置鼻,我覺得這樣就夠了。
所以蜓竹,我覺得用哪種方法都不奇怪箕母,甚至綜合各種因素后,使用H5去做也可以啊俱济。當(dāng)然嘶是,那樣的話,也就沒iOS多少事了蛛碌。