Label設置行間距
內容摘要
- UILabel顯示多行文本
- UILabel設置行間距
- 解決單行文本 & 多行文本顯示的問題
場景描述
- 眾所周知,UILabel顯示多行的話,默認行間距為0,但實際開發中,如果顯示多行文本,一般情況下會有一定的行間距。如果想動態調整行間距,則需要賦值富文本屬性(而不是文本屬性)
問題分析
Label顯示多行文本
- label默認情況下,只會顯示單行文本,主要是因為它的
numberOfLines
屬性值是1
;如果要顯示多行,把這個屬性值改成0
即可。
self.lblResult.numberOfLines = 0;
-
默認情況下,會顯示成這樣:
Label設置行間距_多行0間距.png - 如果想添加行間距,你可能會這樣做:
- 寫一個string轉換成AttributedString的方法(或者給字符串增加一個分類)
-(NSAttributedString *)getAttributedStringWithString:(NSString *)string lineSpace:(CGFloat)lineSpace { NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.lineSpacing = lineSpace; // 調整行間距 NSRange range = NSMakeRange(0, [string length]); [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range]; return attributedString;
}
* 賦值富文本屬性
objc
NSString string = @"眾所周知,UILabel顯示多行的話,默認行間距為0,但實際開發中,如果顯示多行文本,一般情況下會有一定的行間距。如果想動態調整行間距,則需要賦值富文本屬性*(而不是文本屬性)";
// 5:行間距
self.lblResult.attributedText = [self getAttributedStringWithString:string lineSpace:5];
```
-
結果如下圖:
Label設置行間距_多行5間距.png
=============== 華麗的分割線 ===============
</br>
問題:以上方法顯示多行文本貌似沒有問題,但如果文本只有一行呢?
Label顯示單行文本
- 顯示單行中文:
NSString *string = @"文本只有一行會顯示什么樣?";
self.lblResult.attributedText = [self getAttributedStringWithString:string lineSpace:5];
- 顯示單行英文:
NSString *string = @"good good study day day up";
self.lblResult.attributedText = [self getAttributedStringWithString:string lineSpace:5];
- 通過比較發現,用同樣的方法,單行顯示中文 & 英文,效果不同,中文會多了一些空白!心中立馬有種蛋蛋的憂桑,一絲絲凄涼……
遇到問題之后
- 查詢API-
NSMutableParagraphStyle
// Indent:縮進
@property(NS_NONATOMIC_IOSONLY) CGFloat lineSpacing;
@property(NS_NONATOMIC_IOSONLY) CGFloat paragraphSpacing;
@property(NS_NONATOMIC_IOSONLY) NSTextAlignment alignment;
@property(NS_NONATOMIC_IOSONLY) CGFloat firstLineHeadIndent;
@property(NS_NONATOMIC_IOSONLY) CGFloat headIndent;
@property(NS_NONATOMIC_IOSONLY) CGFloat tailIndent;
@property(NS_NONATOMIC_IOSONLY) NSLineBreakMode lineBreakMode;
@property(NS_NONATOMIC_IOSONLY) CGFloat minimumLineHeight;
@property(NS_NONATOMIC_IOSONLY) CGFloat maximumLineHeight;
@property(NS_NONATOMIC_IOSONLY) NSWritingDirection baseWritingDirection;
@property(NS_NONATOMIC_IOSONLY) CGFloat lineHeightMultiple;
@property(NS_NONATOMIC_IOSONLY) CGFloat paragraphSpacingBefore;
@property(NS_NONATOMIC_IOSONLY) float hyphenationFactor;
```
- 各種嘗試之后,問題還在那兒……
- 想到富文本屬性,查詢
NSAttributedString.h
頭文件- 仿佛看到了勝利的曙光
UIKIT_EXTERN NSString * const NSBaselineOffsetAttributeName NS_AVAILABLE(10_0, 7_0); // NSNumber containing floating point value, in points; offset from baseline, default 0
嘗試解決問題
- 重構
getAttributedStringWithString
方法
-(NSAttributedString *)getAttributedStringWithString:(NSString *)string lineSpace:(CGFloat)lineSpace baselineOffset:(CGFloat)baselineOffset {
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = lineSpace; // 調整行間距
NSRange range = NSMakeRange(0, [string length]);
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range];
// 設置文本偏移量
[attributedString addAttribute:NSBaselineOffsetAttributeName value:@(baselineOffset) range:range];
return attributedString;
}
-
于是單行文本顯示成這樣:
Label設置行間距_單行中文5間距偏移量.png
Label設置行間距_單行英文5間距偏移量.png -
那么多行呢?
Label設置行間距_多行中文5間距偏移量.png
Label設置行間距_多行英文5間距偏移量.png
我擦!
問題分析
- 通過上面的示例分析,可以簡單的得到結論:
- 未設置行間距和偏移量,什么問題都沒有,只是行與行之間顯示得比較緊促!
- 只設置行間距,多行和單行英文情況下,顯示沒有問題,但單行中文顯示會有問題,底部會有空白!
- 既設置行間距,也設置偏移的情況下,單行顯示沒有問題,但多行顯示有問題!
解決辦法
- 多行情況下,不設置偏移!
那么問題來了,如何判斷label顯示幾行呢?
- 筆者用比較笨的方法:計算某幾個固定字符的高度,然后再計算label文本的高度,如果后者大于前者,則為多行!
- 示例代碼如下:
CGFloat lineSpace = 5;
CGFloat offset = -(1.0/3 * lineSpace) - 1.0/3;
CGFloat marginLeft = 20;
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineSpacing = lineSpace; // 調整行間距
NSDictionary *attrs = @{
NSFontAttributeName : self.lblResult.font,
NSParagraphStyleAttributeName : paragraphStyle
};
// 計算一行文本的高度
CGFloat oneHeight = [@"測試Test" boundingRectWithSize:CGSizeMake(screenWidth-marginLeft*2, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size.height;
CGFloat rowHeight = [self.txtInputString.text boundingRectWithSize:CGSizeMake(screenWidth-marginLeft*2, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:attrs context:nil].size.height;
// 如果超出一行,則offset=0;
offset = rowHeight > oneHeight ? 0 : offset;
self.lblResult.attributedText = [self getAttributedStringWithString:self.txtInputString.text lineSpace:lineSpace baselineOffset:offset];
- OK,這樣貌似解決了上面的問題,但細心的你估計會發現一個問題:
CGFloat offset = -(1.0/3 * lineSpace) - 1.0/3;
這行代碼是什么意思?
關于 f(x) = -(1.0/3 * x) - 1.0/3
- offset是通過窮舉法歸納總結出來的,也許不夠準確,但在項目中用起來挺好。
- 根據文本內容,描點
// 描點
CGPoint points[15];
// CGPointMake(lineSpace, offset)
points[0] = CGPointMake(5, -2);
points[1] = CGPointMake(8, -3);
points[2] = CGPointMake(10, -3.5);
points[3] = CGPointMake(16, -6);
points[4] = CGPointMake(20, -7);
points[5] = CGPointMake(25, -9);
points[6] = CGPointMake(30, -11);
points[7] = CGPointMake(35, -11.5);
points[8] = CGPointMake(40, -13);
points[9] = CGPointMake(50, -15);
points[10] = CGPointMake(60, -18.5);
points[11] = CGPointMake(70, -23);
points[12] = CGPointMake(80, -26);
points[13] = CGPointMake(90, -29);
points[14] = CGPointMake(100, -32);
// 畫線
[self drawLine:points count:15];
- 畫線
// 畫線
-(void)drawLine:(CGPoint[])points count:(NSInteger)count {
CGMutablePathRef linePath = CGPathCreateMutable();
CGPathAddLines(linePath, NULL, points, count);
// 關聯layer和貝塞爾路徑
self.linesLayer.path = linePath;
CGPathRelease(linePath);
// 創建Animation
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.fromValue = @(0.0);
animation.toValue = @(1.0);
self.linesLayer.autoreverses = NO;
animation.duration = 1.5f;
// 設置layer的animation
[self.linesLayer addAnimation:animation forKey:nil];
self.linesLayer.strokeEnd = 1;
}
![Uploading Label設置行間距_歸納總結offset的算法_323780.png . . .]