iOS開發中我們有時需要代碼預先計算出字符串的寬高來進行特殊布局,在iOS7以后,計算字符串高度使用boundingRectWithSize
方法,
- 創建并設置label控件
UILabel *label = [UILabel new];
label.userInteractionEnabled = NO;
label.textAlignment = NSTextAlignmentCenter;
label.lineBreakMode = NSLineBreakByCharWrapping;
label.numberOfLines = 0;
- 計算字符長度 (一個很長的字符串)
str = @"您邀請\"123\"、\"123\"、...... \"123\"、\"123\"、\"123\"加入了群";
NSDictionary *attributes = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0]};
CGSize textRect = CGSizeMake([UIScreen mainScreen].bounds.size.width - 30, MAXFLOAT);
CGFloat textHeight = [str boundingRectWithSize:textRect
options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading
attributes:attributes
context:nil].size.height;
Bug表現
上述的代碼執行后就會出現高度計算的問題,實際的效果是顯示的文本高度比計算出來的高度少很多,導致出現空白。
然而當我把文本內容全都換成中文以后卻變正常了,這讓人摸不著頭腦。
文本換行樣式
- 以單詞為單位換行
label.lineBreakMode = NSLineBreakByWordWrapping;
這種方式將會包含多種規則
- 英文單詞會作為一個整體不會出現截斷,比如world
- 數字,例如12345也會作為一個整體
- 各種符號不會出現在行的第一個位置,會將上一行的最后單詞移動到下一行. 包括標點符號和其他符號。例如 ,。, - ' "" _ [ 等等;
- 還有很多規則,這些都是為了閱讀起來方便;
- 以字符為單位換行
label.lineBreakMode = NSLineBreakByCharWrapping;
這種方式就比較簡單了,以單個字符為單位,如果一行顯示不下則換到下一行,從左到右連續排版沒有其他規則;
Bug分析
注意上面代碼part1部分UILabel設置的是以字符NSLineBreakByCharWrapping
為單位換行,而文本計算的時候沒有指定換行方式,系統默認的換行方式是以單詞換行,上面代碼中的數字123
和引號\"
還有頓號、
都會被換行規則限定,所以以這種排版計算出來的高度會高很多才導致了這個bug
修正后改后的代碼
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = NSLineBreakByCharWrapping;
NSDictionary * attributes = @{
NSFontAttributeName:font,
NSParagraphStyleAttributeName: paragraphStyle
};
CGSize textRect = CGSizeMake([UIScreen mainScreen].bounds.size.width - 30, MAXFLOAT);
CGFloat textHeight = [str boundingRectWithSize:textRect
options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading
attributes:attributes
context:nil].size.height;