目錄
手寫(xiě)代碼和IB處理tableView動(dòng)態(tài)行高
手寫(xiě)代碼情況下,需要考慮的方面:
一、label單行與多行的區(qū)別
二、手寫(xiě)label背景填充跟著字來(lái)是否麻煩?
三、單行情況下,文字帶中文,設(shè)置行間距,計(jì)算出的高度不準(zhǔn)確。
備注
tableView是我們常用的控件之一,我們來(lái)談一談對(duì)于其行高的動(dòng)態(tài)設(shè)置。
手寫(xiě)代碼:
[string boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size
IB:
設(shè)定位置,不設(shè)定固定高,editor中設(shè)置sizeToFit,在heightForRow方法中給cell賦值后調(diào)用layoutIfNeeded方法。
(若想背景填充跟著字來(lái),設(shè)置label的width的less than最大寬度,字?jǐn)?shù)不足一行的,約束也會(huì)自動(dòng)縮到與label長(zhǎng)度匹配)
由于heightForRow會(huì)調(diào)用多次,在heightForRow中給cell賦值和調(diào)用layoutIfNeeded,性能會(huì)比較差。
解決方案:
1、根據(jù)id緩存每行的高度
2、設(shè)置預(yù)估行高
方案1、減少了調(diào)用cell賦值和layoutIfNeeded,性能相對(duì)提升。但是在獲取行高的方法里進(jìn)行了cell的賦值,結(jié)構(gòu)上不合理。
方案2、在固定行高的情況下合適,動(dòng)態(tài)行高的情況由于預(yù)估行高和實(shí)際行高的不同會(huì)出現(xiàn)列表跳動(dòng)。這樣說(shuō)來(lái),在固定行高的情況下設(shè)置預(yù)估行高能減少heightForRow的調(diào)用,提升性能。
手寫(xiě)和IB的區(qū)別:
手寫(xiě):僅僅是計(jì)算;
IB:程序一啟動(dòng)就會(huì)全部加載進(jìn)內(nèi)存由系統(tǒng)托管,先強(qiáng)制布局然后看占了多大的尺寸。
使用手寫(xiě)代碼的時(shí)候,有些東西需要考慮一下:
一、label單行與多行的區(qū)別
使用NSStringDrawingUsesLineFragmentOrigin
官方文檔的描述:
To correctly draw and size multi-line text, pass NSStringDrawingUsesLineFragmentOrigin in the options parameter.
多行文本draw或者獲取高度,需要有NSStringDrawingUsesLineFragmentOrigin在options參數(shù)中
我看到有不少人使用了NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading
不明白為什么要這樣使用?先看看官方文檔對(duì)兩個(gè)選項(xiàng)的描述:
NSStringDrawingUsesLineFragmentOrigin
The specified origin is the line fragment origin, not the base line origin
指定的原點(diǎn)是行片段的原點(diǎn), 而不是基線原點(diǎn)。
NSStringDrawingUsesFontLeading
Uses the font leading for calculating line heights
使用字體行距計(jì)算行高。
我看到文章有提出
1、NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading這種能解決有時(shí)高度不準(zhǔn)的問(wèn)題
2、在textView中,顯示行數(shù)是10行,使用NSStringDrawingUsesLineFragmentOrigin時(shí)只計(jì)算出了5行的高度,而使用NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading計(jì)算出了10行的高度
針對(duì)這兩個(gè)情況:
1、目前我使用中文、英文和中英文混合,使用NSStringDrawingUsesLineFragmentOrigin和使用NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading的效果一樣。
2、我通過(guò)UIFont獲取字高度,textView顯示了多少行,算出這幾行的高度,然后這些文字通過(guò)boundingRectWithSize:options: attributes: context:方法計(jì)算一下高度,發(fā)現(xiàn)使用NSStringDrawingUsesLineFragmentOrigin沒(méi)問(wèn)題。
UIFont中找到了兩個(gè)屬性:ascender、capHeight。第一個(gè)可以得到中文字體的實(shí)際顯示大小,第二個(gè)可以得到英文字母和數(shù)字的實(shí)際顯示大小
這樣看來(lái)使用要不要NSStringDrawingUsesFontLeading都一樣,如果有不同的意見(jiàn),請(qǐng)?jiān)谙路皆u(píng)論。
二、剛剛看IB背景填充跟著字?jǐn)?shù)來(lái)好像很簡(jiǎn)單,那么手寫(xiě)label背景填充跟著字來(lái)是否麻煩?
使用attributedText即可,好像也不麻煩。
三、單行情況下,文字帶中文,設(shè)置行間距,計(jì)算出的高度不準(zhǔn)確。
那么看看我們需要先確定的判斷條件:
1、是否設(shè)置行間距;
2、是否是單行;
3、是否帶中文;

那么如果滿足這三種情況的話,我將size高度中的lineSpacing減掉不就可以了,那么看代碼

這個(gè)時(shí)候運(yùn)行后會(huì)發(fā)現(xiàn)還是有問(wèn)題,size對(duì)了,但是label設(shè)置attributedText時(shí)帶了lineSpacing,字的顯示不對(duì),那么我需要將attributedText中的lineSpacing也去掉。

這個(gè)時(shí)候沒(méi)問(wèn)題了。以上方法都放在NSString+Private文件中。
備注:
官方文檔:
This method returns fractional sizes (in the size component of the returned CGRect); to use a returned size to size views, you must raise its value to the nearest higher integer using the ceil function.
獲取的CGRect的值用一下ceil方法