Label設(shè)置行間距
內(nèi)容摘要
- UILabel顯示多行文本
- UILabel設(shè)置行間距
- 解決單行文本 & 多行文本顯示的問題
場景描述
- 眾所周知球化,UILabel顯示多行的話,默認(rèn)行間距為0蛔趴,但實際開發(fā)中,如果顯示多行文本,一般情況下會有一定的行間距谢揪。如果想動態(tài)調(diào)整行間距,則需要賦值富文本屬性(而不是文本屬性)
問題分析
Label顯示多行文本
- label默認(rèn)情況下捐凭,只會顯示單行文本拨扶,主要是因為它的
numberOfLines
屬性值是1
;如果要顯示多行茁肠,把這個屬性值改成0
即可患民。
self.lblResult.numberOfLines = 0;
-
默認(rèn)情況下,會顯示成這樣:
- 如果想添加行間距垦梆,你可能會這樣做:
- 寫一個string轉(zhuǎn)換成AttributedString的方法(或者給字符串增加一個分類)
-(NSAttributedString *)getAttributedStringWithString:(NSString *)string lineSpace:(CGFloat)lineSpace { NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string]; NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; paragraphStyle.lineSpacing = lineSpace; // 調(diào)整行間距 NSRange range = NSMakeRange(0, [string length]); [attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range]; return attributedString;
}
* 賦值富文本屬性
objc
NSString string = @"眾所周知匹颤,UILabel顯示多行的話,默認(rèn)行間距為0托猩,但實際開發(fā)中印蓖,如果顯示多行文本,一般情況下會有一定的行間距京腥。如果想動態(tài)調(diào)整行間距另伍,則需要賦值富文本屬性*(而不是文本屬性)";
// 5:行間距
self.lblResult.attributedText = [self getAttributedStringWithString:string lineSpace:5];
```
-
結(jié)果如下圖:
=============== 華麗的分割線 ===============
</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];
- 通過比較發(fā)現(xiàn)温艇,用同樣的方法,單行顯示中文 & 英文堕汞,效果不同勺爱,中文會多了一些空白!心中立馬有種蛋蛋的憂桑讯检,一絲絲凄涼……
遇到問題之后
- 查詢API-
NSMutableParagraphStyle
// Indent:縮進(jìn)
@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
嘗試解決問題
- 重構(gòu)
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; // 調(diào)整行間距
NSRange range = NSMakeRange(0, [string length]);
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:range];
// 設(shè)置文本偏移量
[attributedString addAttribute:NSBaselineOffsetAttributeName value:@(baselineOffset) range:range];
return attributedString;
}
-
于是單行文本顯示成這樣:
-
那么多行呢人灼?
我擦围段!
問題分析
- 通過上面的示例分析,可以簡單的得到結(jié)論:
- 未設(shè)置行間距和偏移量投放,什么問題都沒有奈泪,只是行與行之間顯示得比較緊促!
- 只設(shè)置行間距灸芳,多行和單行英文情況下涝桅,顯示沒有問題,但單行中文顯示會有問題烙样,底部會有空白冯遂!
- 既設(shè)置行間距,也設(shè)置偏移的情況下谒获,單行顯示沒有問題蛤肌,但多行顯示有問題!
解決辦法
- 多行情況下批狱,不設(shè)置偏移裸准!
那么問題來了,如何判斷l(xiāng)abel顯示幾行呢精耐?
- 筆者用比較笨的方法:計算某幾個固定字符的高度狼速,然后再計算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; // 調(diào)整行間距
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恼蓬,這樣貌似解決了上面的問題惊完,但細(xì)心的你估計會發(fā)現(xiàn)一個問題:
CGFloat offset = -(1.0/3 * lineSpace) - 1.0/3;
這行代碼是什么意思?
關(guān)于 f(x) = -(1.0/3 * x) - 1.0/3
- offset是通過窮舉法歸納總結(jié)出來的处硬,也許不夠準(zhǔn)確小槐,但在項目中用起來挺好。
- 根據(jù)文本內(nèi)容,描點
// 描點
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);
// 關(guān)聯(lián)layer和貝塞爾路徑
self.linesLayer.path = linePath;
CGPathRelease(linePath);
// 創(chuàng)建Animation
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.fromValue = @(0.0);
animation.toValue = @(1.0);
self.linesLayer.autoreverses = NO;
animation.duration = 1.5f;
// 設(shè)置layer的animation
[self.linesLayer addAnimation:animation forKey:nil];
self.linesLayer.strokeEnd = 1;
}
![Uploading Label設(shè)置行間距_歸納總結(jié)offset的算法_323780.png . . .]