iOS lineSpacing行間距無效

在我們開發過程中會遇到,當你的文字很大時,會出現下面的現象


此時的代碼如下:


//行間距減去 12  上14
    NSMutableParagraphStyle *paraStyle = [[NSMutableParagraphStyle alloc] init];
    paraStyle.lineBreakMode = NSLineBreakByCharWrapping;
    //paraStyle.lineSpacing = 20;
    //設置負數沒有效果的
    //paraStyle.lineSpacing = 5 + 15;
    paraStyle.lineSpacing = 0;

    paraStyle.alignment = NSTextAlignmentRight;
    NSDictionary *attributes = @{NSParagraphStyleAttributeName : paraStyle};
    NSMutableAttributedString * astr = [[NSMutableAttributedString alloc] initWithString:self.lab.text attributes:attributes];
    NSDictionary *attribute = @{NSForegroundColorAttributeName : [UIColor blackColor], NSFontAttributeName : [UIFont systemFontOfSize:40]};
    [astr addAttributes:attribute range:NSMakeRange(0, self.lab.text.length)];
    self.lab.attributedText = astr;

此時我設置的lineSpacing是0,但是圖片上的文字間距還是很大,怎麼改lineSpacing,都沒有效果,那如何解決這個問題呢?

正確的實現行間距


紅色區域是默認繪製單行文本會佔用的區域,可以看到文字的上下是有一些留白的(藍色和紅色重疊的部分)。設計師是想要藍色區域高度爲 10pt,而我們直接設置 lineSpacing 會將兩行紅色區域中間的綠色區域高度設置爲 10pt,這就是問題的根源了。

那麼這個紅色的區域高度是多少呢?答案是 label.font.lineHeight,它是使用指定字體繪製單行文本的原始行高。

知道了原因後問題就好解決了,我們需要在設置 lineSpacing 時,減去這個系統的自帶邊距:

NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    /**zhushi
     (lldb) po _moveTipLabel.font.lineHeight
     47.734375
     (lldb) po _moveTipLabel.font.pointSize
     40
     */
    paragraphStyle.lineSpacing = 10 - (_moveTipLabel.font.lineHeight - _moveTipLabel.font.pointSize);
    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
    [attributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
    _moveTipLabel.attributedText = [[NSAttributedString alloc] initWithString:_moveTipLabel.text attributes:attributes];
    

觀察一下效果,完美契合:


關於行高 lineHeight

如果你只關心 iOS 設備上的文本展示效果,那麼看到這裏就已經夠了。但是我需要的是 iOS 和 Android 展現出一模一樣的效果,所以光有行間距是不能滿足需求的。主要的原因在前言也提到了,Android 設備上的文字上下默認留白(上一節圖中藍色和紅色重疊的部分)和 iOS 設備上的是不一致的:

左側是 iOS 設備,右側 Android 設備,可以看到同樣是顯示 20 號的字體,安卓的行高會偏高一些。在不同的 Android 設備上使用的字體不一樣,可能還會出現更多的差別。如果不想辦法抹平這差別,就不能真正意義上實現雙端一致了。

這時候我們可以通過設置 lineHeight 來使得每一行文本的高度一致,lineHeight 設置爲 30pt 的情況下,一行文本高度一定是 30pt,兩行文本高度一定是 60pt。雖然文字的渲染上會有細微的差別,但是佈局上的差別將被完全的抹除。lineHeight 同樣可以藉助 NSAttributedString 來實現,示意代碼:

CGFloat lineHeight = 20;
    
    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    paragraphStyle.maximumLineHeight = lineHeight;
    paragraphStyle.minimumLineHeight = lineHeight;
    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
    [attributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
    _lab.attributedText = [[NSAttributedString alloc] initWithString:_lab.text attributes:attributes];

運行一下觀察效果:



在 debug 模式下確認了下文本的高度的確正確的,但是爲什麼文字都顯示在了行底呢?

修正行高增加後文字的位置

修正文字在行中展示的位置,我們可以用baselineOffset 屬性來搞定。這個屬性十分有用,在實現上標下標之類的需求時也經常用到它。經過調試,發現最合適的值是 (lineHeight - label.font.lineHeight) / 4(尚未搞清楚爲什麼是除以 4 而不是除以 2,希望知道的老司機指點一二)。最終的代碼示例如下:

 #pragma mark - 333
    CGFloat lineHeight = 20;
    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    paragraphStyle.maximumLineHeight = lineHeight;
    paragraphStyle.minimumLineHeight = lineHeight;
    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
    [attributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
    CGFloat baselineOffset = (lineHeight - _lab.font.lineHeight) / 4;
    [attributes setObject:@(baselineOffset) forKey:NSBaselineOffsetAttributeName];
    _lab.attributedText = [[NSAttributedString alloc] initWithString:_lab.text attributes:attributes];
    

貼一下在不同字號和行高下的展示效果:


行高和行間距同時使用時的一個問題

不得不說行高和行間距我們都已經可以完美的實現了,但是我在嘗試同時使用它們時,發現了 iOS 的一個 bug(當然也可能是一個 feature,畢竟不 crash 都不一定是 bug):



着色的區域都是文本的繪製區域,其中看上去是橙色的區域是 lineSpacing,綠色的區域是 lineHeight。但是爲什麼單行的文本系統也要展示一個 lineSpacing 啊!?坑爹呢這是!?

好在我們通常是行高和行間距針對不同的需求分別獨立使用的,它們在分開使用時不會觸發這個問題。so 暫且將高度計算的邏輯保持和系統一致了。

那麼本文開頭我提出問題的解決方式如下,親測有效

 CGFloat lineHeight = 45;
    NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
    paragraphStyle.maximumLineHeight = lineHeight;
    paragraphStyle.minimumLineHeight = lineHeight;
    NSMutableDictionary *attributes = [NSMutableDictionary dictionary];
    [attributes setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
    
    CGFloat baselineOffset = (lineHeight - _lab.font.lineHeight) / 4;
    
    //[attributes setObject:@(baselineOffset) forKey:NSBaselineOffsetAttributeName];
    
    [attributes setObject:@1 forKey:NSBaselineOffsetAttributeName];
    
    _lab.attributedText = [[NSAttributedString alloc] initWithString:_lab.text attributes:attributes];
    

本文摘自蘋果核
講解行間距,很詳細,僅供學習!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章