引言
由于最近工作需要實現一個類似脈脈動態的界面,其中展開顯示全文功能,需要動態計算Label的大小后決定隱藏或者顯示,之前一直使
- (CGSize)sizeWithFont:(UIFont *)font
方法,而在iOS7中用方法- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSString *, id> *)attributes context:(nullable NSStringDrawingContext *)context
,但是在實際運用中發現還是有一點小誤差的。
關鍵字:全文
、Label高度計算
、展開全文
1 函數介紹
1.1 描述
- (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(NSDictionary<NSString *,id> *)attributes context:(NSStringDrawingContext *)context;
根據上下文設定和顯示特性計算并返回一個rect大小
1.2 參數
參數 | 說明 |
---|---|
size | 存放字符串的Label的size大小 |
options | 字符串排版的選項(下文會說明) |
attributes | 文字屬性設置,至少需要font屬性 |
context | 渲染上下文 |
1.2.1 關于options
options | 說明 |
---|---|
NSStringDrawingTruncatesLastVisibleLine | 如果文本內容超出指定的矩形限制,文本將被截去并在最后一個字符后加上省略號。 |
NSStringDrawingUsesLineFragmentOrigin | 啟用自動換行 |
NSStringDrawingUsesFontLeading | 計算行高時使用行間距 |
NSStringDrawingUsesDeviceMetrics | 計算布局時使用圖元字形(而不是印刷字體) |
- 一般我們使用
NSStringDrawingUsesLineFragmentOrigin
和NSStringDrawingUsesFontLeading
即可。
2 使用
直接上代碼
NSString *contentText = @"南美足聯同意國民競技隊請求,沙佩科恩斯隊將獲南美杯冠軍。南美足聯同意國民競技隊請求,沙佩科恩斯隊將獲南美杯冠軍。南美足聯同意國民競技隊請求,沙佩科恩斯隊將獲南美杯冠軍。";
UILabel *DisplayLabel = [[UILabel alloc] init];
DisplayLabel.numberOfLines = 0;
DisplayLabel.text = contentText;
DisplayLabel.textColor = [UIColor orangeColor];
DisplayLabel.font = [UIFont systemFontOfSize:17];
DisplayLabel.frame = CGRectMake(20, 70, 200, 200);
[DisplayLabel sizeToFit];
DisplayLabel.backgroundColor = [UIColor greenColor];
[self.view addSubview:DisplayLabel];
//至少設置一個font屬性
UIFont *fnt = self.DisplayLabel.font;
NSDictionary *dict = @{NSFontAttributeName: fnt};
//在為達到高度的情況下只有label的寬度有約束作用,高度最多為1000
CGSize defineSize = CGSizeMake(DisplayLabel.bounds.size.width, 1000);
//rect內的size即為計算所得的label大小
CGRect rect = [contentText boundingRectWithSize:defineSize
options:NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:dict
context:nil];
結果顯示
Simulator Screen Shot 2016年12月3日 下午3.00.13.png
- 結果上會有小數點后一位的誤差,需要各位爺自己調整下,如果有好的建議歡迎指教~
3 附加
- 展開顯示全文的功能有時候還能通過計算行數來實現,送上一個coreText下的計算行數及每行內容的方法
//數組內為每行的內容,數組的count為行數
- (NSArray *)getLinesArrayOfStringInLabel:(UILabel *)label{
NSString *text = [label text];
UIFont *font = [label font];
//目的為了取到label的寬度
CGRect rect = [label frame];
CTFontRef myFont = CTFontCreateWithName(( CFStringRef)([font fontName]), [font pointSize], NULL);
NSMutableAttributedString *attStr = [[NSMutableAttributedString alloc] initWithString:text];
[attStr addAttribute:(NSString *)kCTFontAttributeName value:(__bridge id)myFont range:NSMakeRange(0, attStr.length)];
CFRelease(myFont);
CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString(( CFAttributedStringRef)attStr);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(0,0,rect.size.width,100000));
CTFrameRef frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);
NSArray *lines = ( NSArray *)CTFrameGetLines(frame);
NSMutableArray *linesArray = [[NSMutableArray alloc]init];
for (id line in lines) {
CTLineRef lineRef = (__bridge CTLineRef )line;
CFRange lineRange = CTLineGetStringRange(lineRef);
NSRange range = NSMakeRange(lineRange.location, lineRange.length);
NSString *lineString = [text substringWithRange:range];
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithFloat:0.0]));
CFAttributedStringSetAttribute((CFMutableAttributedStringRef)attStr, lineRange, kCTKernAttributeName, (CFTypeRef)([NSNumber numberWithInt:0.0]));
[linesArray addObject:lineString];
}
CFRelease(frameSetter);
CFRelease(frame);
CFRelease(path);
return (NSArray *)linesArray;
}
最后附上github的demo。
歡迎各位看官老爺指教~