? 在iOS的開(kāi)發(fā)過(guò)程中,UITableView的使用頻次是非常高的,用來(lái)加載具有一定規(guī)則的的cell來(lái)呈現(xiàn)更多的展示內(nèi)容.而根據(jù)規(guī)則的不同我們也要對(duì)cell做出相應(yīng)的改變--自定義cell.使用自定義cell就不得不說(shuō)一下cell的高度計(jì)算.
在iOS6以前
手機(jī)坐標(biāo)寬度為固定的320,cell內(nèi)部的布局基本都是依靠setFrame方法.也就是說(shuō)cell的橫向布局基本都是固定的(有的可能在橫向也會(huì)做出改變,但這些都可以提前計(jì)算出寬度).
- (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];
//?計(jì)算出顯示完內(nèi)容需要的最小尺寸
CGSize?size?=?[content?sizeWithFont:font?constrainedToSize:CGSizeMake(contentWidth,?1000.0f)?lineBreakMode:UILineBreakModeWordWrap];
//?這裏返回需要的高度
returnsize.height+20;
}
使用這種方法,乍看是沒(méi)什么問(wèn)題的,但是我們知道每次reloadData的時(shí)候都會(huì)先走這個(gè)代理方法來(lái)計(jì)算所有cell的高度.也就是說(shuō)如果tableView中有100個(gè)cell的話,它會(huì)先走100次,然后在滑動(dòng)tableView讓cell出現(xiàn)的時(shí)候會(huì)在計(jì)算一次.這意味著每次tableView在顯示之前都要在主線程做出大量的計(jì)算.如果cell做的比較復(fù)雜可能還會(huì)出現(xiàn)滑動(dòng)卡頓的情況.一般碰到這種情況,我們會(huì)在得到數(shù)據(jù)源的同時(shí)通過(guò)sizeWithFont:constrainedToSizelineBreakMode:方法來(lái)得到高度,并將高度保存在數(shù)組中.
如果cell比較復(fù)雜,造成滑動(dòng)卡頓,那我們就得從cell本身下手了(產(chǎn)品經(jīng)理,你的需求臣妾做不到啊):
1,復(fù)用cell.這個(gè)應(yīng)該不用多說(shuō)了吧.另外xib寫(xiě)的cell可以在右邊直接注冊(cè)復(fù)用標(biāo)識(shí)符的.
2,減少視圖的數(shù)目.view是是一個(gè)很大的對(duì)象,創(chuàng)建它需要消耗很大的資源并且影響渲染速度.所以還是多使用屬性字符串來(lái)減少視圖的數(shù)量.如果你們的產(chǎn)品對(duì)滑動(dòng)要求很苛刻,而你又恰好有大量的時(shí)間的話,可以考慮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í)能很大程度的提高流暢度,但是會(huì)給開(kāi)發(fā)和維護(hù)造成很大的難度.
3,不要阻塞主線程.不要再滑動(dòng)的時(shí)候讓主線程執(zhí)行耗時(shí)的方法,如圖片請(qǐng)求.
其實(shí)主要的方法就這幾個(gè),之前百度了幾篇文章,講的很細(xì),但是在巨大多數(shù)開(kāi)發(fā)過(guò)程中真正會(huì)用到的也就這幾種.
iOS6之后
iOS6之后蘋(píng)果引入了自動(dòng)布局(主要針對(duì)不同屏幕寬度做適配),我們也將cell的布局從setFrame方法變?yōu)榱颂砑蛹s束,在配合x(chóng)ib的使用也極大的提高了開(kāi)發(fā)速度.在很長(zhǎng)一段時(shí)間里,我是不大喜歡用xib+autoLayout來(lái)開(kāi)發(fā)的,因?yàn)楫?dāng)時(shí)會(huì)覺(jué)得,xib寫(xiě)的cell的可變動(dòng)性太小了,而且高度也不大好計(jì)算.但是在后來(lái)的開(kāi)發(fā)和學(xué)習(xí)后,我基本寫(xiě)cell都會(huì)使用xib加約束.
iOS6之后,引入了一個(gè)新的方法來(lái)計(jì)算cell的高度
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize;
首先,創(chuàng)建一個(gè)UITableViewCell的子類,在cell上添加視圖,然后給視圖添加各種約束.注意添加約束的時(shí)候一定要有上下關(guān)聯(lián)(也就是說(shuō)最上的視圖對(duì)contentView有top約束,最下的視圖對(duì)contentView有bottom的約束,兩個(gè)視圖就要有直接或者間接的縱向約束).然后按照如下方法就能得到高度.
- (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)你嘗試這種方法的時(shí)候,你會(huì)發(fā)現(xiàn)為什么我設(shè)置numberOfLines=0并且字?jǐn)?shù)明顯超過(guò)了一行,它為什么不換行.這時(shí)候你只用給需要換行的label加上preferredMaxLayoutWidth就好了.
self.medicineNameLabel.preferredMaxLayoutWidth=SCREEN_WIDTH-60;
這樣他就能正常換行并且自動(dòng)計(jì)算高度了.
但是這樣你依舊會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題,就是在得到數(shù)據(jù)源同時(shí)來(lái)計(jì)算cell的高度變麻煩了.我必須創(chuàng)建一個(gè)專門(mén)計(jì)算高度的cell來(lái)計(jì)算高度.
然而iOS7用給我們帶來(lái)了一個(gè)新的方法.
- (CGFloat)tableView:(UITableView*)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath*)indexPath
如果實(shí)現(xiàn)了這個(gè)代理方法,那么在tableView reloadData時(shí)將不在一次性執(zhí)行100次cell高度的計(jì)算方法,而是將上面這個(gè)代理方法返回的值作為cell的預(yù)估高度.如果cell比較少,且預(yù)估高度和實(shí)際高度相差比較大的情況下滑動(dòng)tableView,你會(huì)發(fā)現(xiàn)滾動(dòng)條在跳動(dòng).
總覺(jué)得這個(gè)方法有點(diǎn)得不償失,提高刷新速度的同時(shí),反而降低了滑動(dòng)的流暢程度.
iOS8之后,蘋(píng)果對(duì)這個(gè)方法做了改進(jìn).如果你的cell中的約束符合規(guī)范
在寫(xiě)了
- (CGFloat)tableView:(UITableView*)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath*)indexPath
方法后,可以不用寫(xiě)
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath
而且滑動(dòng)效率也有所提高.
UITableView作為iOS開(kāi)發(fā)中最重要的一個(gè)控件,蘋(píng)果也不停的在對(duì)其作出更多的優(yōu)化.值得慶幸的是,適配并不麻煩.否則真的是嗶了狗了...