? 在iOS的開發(fā)過程中,UITableView的使用頻次是非常高的,用來加載具有一定規(guī)則的的cell來呈現(xiàn)更多的展示內(nèi)容.而根據(jù)規(guī)則的不同我們也要對cell做出相應(yīng)的改變--自定義cell.使用自定義cell就不得不說一下cell的高度計算.
在iOS6以前
手機(jī)坐標(biāo)寬度為固定的320,cell內(nèi)部的布局基本都是依靠setFrame方法.也就是說cell的橫向布局基本都是固定的(有的可能在橫向也會做出改變,但這些都可以提前計算出寬度).
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
introw?=?[indexPath?row];
//?列寬
CGFloat?contentWidth?=?self.tv.frame.size.width;
//?用何種字體進(jìn)行顯示
UIFont?*font?=?[UIFont?systemFontOfSize:14];
//?該行要顯示的內(nèi)容
NSString?*content?=?[_arr?objectAtIndex:row];
//?計算出顯示完內(nèi)容需要的最小尺寸
CGSize?size?=?[content?sizeWithFont:font?constrainedToSize:CGSizeMake(contentWidth,?1000.0f)?lineBreakMode:UILineBreakModeWordWrap];
//?這裏返回需要的高度
returnsize.height+20;
}
使用這種方法,乍看是沒什么問題的,但是我們知道每次reloadData的時候都會先走這個代理方法來計算所有cell的高度.也就是說如果tableView中有100個cell的話,它會先走100次,然后在滑動tableView讓cell出現(xiàn)的時候會在計算一次.這意味著每次tableView在顯示之前都要在主線程做出大量的計算.如果cell做的比較復(fù)雜可能還會出現(xiàn)滑動卡頓的情況.一般碰到這種情況,我們會在得到數(shù)據(jù)源的同時通過sizeWithFont:constrainedToSizelineBreakMode:方法來得到高度,并將高度保存在數(shù)組中.
如果cell比較復(fù)雜,造成滑動卡頓,那我們就得從cell本身下手了(產(chǎn)品經(jīng)理,你的需求臣妾做不到啊):
1,復(fù)用cell.這個應(yīng)該不用多說了吧.另外xib寫的cell可以在右邊直接注冊復(fù)用標(biāo)識符的.

2,減少視圖的數(shù)目.view是是一個很大的對象,創(chuàng)建它需要消耗很大的資源并且影響渲染速度.所以還是多使用屬性字符串來減少視圖的數(shù)量.如果你們的產(chǎn)品對滑動要求很苛刻,而你又恰好有大量的時間的話,可以考慮drawRect
- (void)drawRect:(CGRect)rect { if (image) { [image drawAtPoint:imagePoint]; self.image = nil; } else { [placeHolder drawAtPoint:imagePoint]; } [text drawInRect:textRect withFont:font lineBreakMode:UILineBreakModeTailTruncation]; }
這樣確實(shí)能很大程度的提高流暢度,但是會給開發(fā)和維護(hù)造成很大的難度.
3,不要阻塞主線程.不要再滑動的時候讓主線程執(zhí)行耗時的方法,如圖片請求.
其實(shí)主要的方法就這幾個,之前百度了幾篇文章,講的很細(xì),但是在巨大多數(shù)開發(fā)過程中真正會用到的也就這幾種.
iOS6之后
iOS6之后蘋果引入了自動布局(主要針對不同屏幕寬度做適配),我們也將cell的布局從setFrame方法變?yōu)榱颂砑蛹s束,在配合xib的使用也極大的提高了開發(fā)速度.在很長一段時間里,我是不大喜歡用xib+autoLayout來開發(fā)的,因為當(dāng)時會覺得,xib寫的cell的可變動性太小了,而且高度也不大好計算.但是在后來的開發(fā)和學(xué)習(xí)后,我基本寫cell都會使用xib加約束.
iOS6之后,引入了一個新的方法來計算cell的高度
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize;
首先,創(chuàng)建一個UITableViewCell的子類,在cell上添加視圖,然后給視圖添加各種約束.注意添加約束的時候一定要有上下關(guān)聯(lián)(也就是說最上的視圖對contentView有top約束,最下的視圖對contentView有bottom的約束,兩個視圖就要有直接或者間接的縱向約束).然后按照如下方法就能得到高度.
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath;
{
EpListCell*cell = (EpListCell*)[selftableView:_tableViewcellForRowAtIndexPath:indexPath];
[cellsetNeedsUpdateConstraints];
[cellupdateConstraintsIfNeeded];
CGSizesize = [cell.contentViewsystemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
returnsize.height+1.0f;//contenView高度和cell高度相差1
}
當(dāng)你嘗試這種方法的時候,你會發(fā)現(xiàn)為什么我設(shè)置numberOfLines=0并且字?jǐn)?shù)明顯超過了一行,它為什么不換行.這時候你只用給需要換行的label加上preferredMaxLayoutWidth就好了.
self.medicineNameLabel.preferredMaxLayoutWidth=SCREEN_WIDTH-60;
這樣他就能正常換行并且自動計算高度了.
但是這樣你依舊會發(fā)現(xiàn)一個問題,就是在得到數(shù)據(jù)源同時來計算cell的高度變麻煩了.我必須創(chuàng)建一個專門計算高度的cell來計算高度.
然而iOS7用給我們帶來了一個新的方法.
- (CGFloat)tableView:(UITableView*)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath*)indexPath
如果實(shí)現(xiàn)了這個代理方法,那么在tableView reloadData時將不在一次性執(zhí)行100次cell高度的計算方法,而是將上面這個代理方法返回的值作為cell的預(yù)估高度.如果cell比較少,且預(yù)估高度和實(shí)際高度相差比較大的情況下滑動tableView,你會發(fā)現(xiàn)滾動條在跳動.
總覺得這個方法有點(diǎn)得不償失,提高刷新速度的同時,反而降低了滑動的流暢程度.
iOS8之后,蘋果對這個方法做了改進(jìn).如果你的cell中的約束符合規(guī)范
在寫了
- (CGFloat)tableView:(UITableView*)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath*)indexPath
方法后,可以不用寫
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
而且滑動效率也有所提高.
UITableView作為iOS開發(fā)中最重要的一個控件,蘋果也不停的在對其作出更多的優(yōu)化.值得慶幸的是,適配并不麻煩.否則真的是嗶了狗了...