61

我对 Core Text 的行距一无所知。我正在使用 NSAttributedString 并在其上指定以下属性: - kCTFontAttributeName - kCTParagraphStyleAttributeName

由此创建 CTFrameSetter 并将其绘制到上下文中。

在段落样式属性中,我想指定行的高度。

当我使用 kCTParagraphStyleSpecifierLineHeightMultiple 时,每行都会在文本顶部接收填充,而不是在此高度的中间显示文本。

当我使用 kCTParagraphStyleSpecifierLineSpacing 时,会在文本底部添加一个填充。

请帮助我使用位于该高度中间的文本(字形)来实现指定的行高,而不是位于行底部或顶部的文本。

如果不遵循明确创建 CTLine 等的路线,这是不可能的吗?

4

10 回答 10

120

Objective-C

NSInteger strLength = [myString length];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:24];
[attString addAttribute:NSParagraphStyleAttributeName
                  value:style
                  range:NSMakeRange(0, strLength)];

斯威夫特 5

let strLength = myString.length()
var style = NSMutableParagraphStyle()
style.lineSpacing = 24
attString.addAttribute(.paragraphStyle, value: style, range: NSRange(location: 0, length: strLength))
于 2013-05-02T12:21:14.430 回答
11

我仍然对我的以下陈述不是 100% 有信心,但这似乎是有道理的。请纠正我哪里错了。

行高(前导)是指连续文字行的基线之间的距离。这里的基线可以解释为文本所在的假想线。

间距是线条之间的间距。空格出现在文本行之后。

我最终使用以下解决方案来解决我的问题:

// NOT SURE WHAT THE THEORY BEHIND THIS FACTOR IS. WAS FOUND VIA TRIAL AND ERROR.
    CGFloat factor = 14.5/30.5;
    CGFloat floatValues[4];
    floatValues[0] = self.lineHeight * factor/(factor + 1);
    floatValues[1] = self.lineHeight/(factor + 1);
    floatValues[2] = self.lineHeight;

此矩阵与 NSAttributedString 的段落样式参数一起使用:

CTParagraphStyleSetting paragraphStyle[3];

paragraphStyle[0].spec = kCTParagraphStyleSpecifierLineSpacing;
paragraphStyle[0].valueSize = sizeof(CGFloat);
paragraphStyle[0].value = &floatValues[0];

paragraphStyle[1].spec = kCTParagraphStyleSpecifierMinimumLineHeight;
paragraphStyle[1].valueSize = sizeof(CGFloat);
paragraphStyle[1].value = &floatValues[1];

paragraphStyle[2].spec = kCTParagraphStyleSpecifierMaximumLineHeight;
paragraphStyle[2].valueSize = sizeof(CGFloat);
paragraphStyle[2].value = &floatValues[2];

CTParagraphStyleRef style = CTParagraphStyleCreate((const CTParagraphStyleSetting*) &paragraphStyle, 3);
[attributedString addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)style range:NSMakeRange(0, [string length])];
CFRelease(style);

希望这可以帮助某人。当我发现更多相关信息时,我会更新这个答案。

于 2011-11-17T06:15:57.407 回答
9

斯威夫特 3中:

    let textFont = UIFont(name: "Helvetica Bold", size: 20)!
    let textColor = UIColor(white: 1, alpha: 1)      // White
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.paragraphSpacing = 20             // Paragraph Spacing
    paragraphStyle.lineSpacing = 40                  // Line Spacing

    let textFontAttributes = [
        NSFontAttributeName: textFont,
        NSForegroundColorAttributeName: textColor,
        NSParagraphStyleAttributeName: paragraphStyle
        ] as [String : Any]
于 2017-04-25T18:19:40.030 回答
8

您可以从情节提要以及以编程方式设置/更新行距和行高倍数。

从界面生成器:

在此处输入图像描述

以编程方式:

斯威夫特 4

extension UILabel {

    // Pass value for any one of both parameters and see result
    func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {

        guard let labelText = self.text else { return }

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = lineSpacing
        paragraphStyle.lineHeightMultiple = lineHeightMultiple

        let attributedString:NSMutableAttributedString
        if let labelattributedText = self.attributedText {
            attributedString = NSMutableAttributedString(attributedString: labelattributedText)
        } else {
            attributedString = NSMutableAttributedString(string: labelText)
        }

        // Line spacing attribute

// Swift 4.2++


attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))

// Swift 4.1--
attributedString.addAttribute(NSAttributedStringKey.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))

        self.attributedText = attributedString
    }
}

现在呼叫分机功能

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"

// Pass value for any one argument - lineSpacing or lineHeightMultiple
label.setLineSpacing(lineSpacing: 2.0) .  // try values 1.0 to 5.0

// or try lineHeightMultiple
//label.setLineSpacing(lineHeightMultiple = 2.0) // try values 0.5 to 2.0

或使用标签实例(只需复制并执行此代码即可查看结果)

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40

// Swift 4.2++
// Line spacing attribute
attrString.addAttribute(NSAttributedString.Key.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))

// Character spacing attribute
attrString.addAttribute(NSAttributedString.Key.kern, value: 2, range: NSMakeRange(0, attrString.length))


// Swift 4.1--
// Line spacing attribute
attrString.addAttribute(NSAttributedStringKey.paragraphStyle, value: style, range: NSRange(location: 0, length: stringValue.characters.count))

// Character spacing attribute
attrString.addAttribute(NSAttributedStringKey.kern, value: 2, range: NSMakeRange(0, attrString.length))

label.attributedText = attrString

斯威夫特 3

let label = UILabel()
let stringValue = "How to\ncontrol\nthe\nline spacing\nin UILabel"
let attrString = NSMutableAttributedString(string: stringValue)
var style = NSMutableParagraphStyle()
style.lineSpacing = 24 // change line spacing between paragraph like 36 or 48
style.minimumLineHeight = 20 // change line spacing between each line like 30 or 40
attrString.addAttribute(NSParagraphStyleAttributeName, value: style, range: NSRange(location: 0, length: stringValue.characters.count))
label.attributedText = attrString
于 2017-10-11T10:46:20.330 回答
4

我尝试了所有这些答案,但要真正获得通常来自 Sketch 或 Zeplin 的设计文件中的精确线高,那么您需要:

let ps = NSMutableParagraphStyle()
ps.minimumLineHeight = 34
ps.maximumLineHeight = 34
let attrText = NSAttributedString(
    string: "Your long multiline text that will have exact line height spacing",
    attributes: [
        .paragraphStyle: ps
    ]
)
someLabel.attributedText = attrText
someLabel.numberOfLines = 2
...
于 2019-08-08T11:00:40.710 回答
3

我为此做了一个扩展,见下文。使用扩展,您可以像这样设置行高:

let label = UILabel()
label.lineHeight = 19 

这是扩展:

// Put this in a file called UILabel+Lineheight.swift, or whatever else you want to call it

import UIKit

extension UILabel {

    var lineHeight: CGFloat {
        set {
            let paragraphStyle = NSMutableParagraphStyle()
            paragraphStyle.minimumLineHeight = newValue
            paragraphStyle.maximumLineHeight = newValue
            _setAttribute(key: NSAttributedString.Key.paragraphStyle, value: paragraphStyle)
        }
        get {
            let paragraphStyle = _getAttribute(key: NSAttributedString.Key.paragraphStyle) as? NSParagraphStyle
            return paragraphStyle?.minimumLineHeight ?? 0
        }
    }

    func _getAttribute(key: NSAttributedString.Key) -> Any? {
        return attributedText?.attribute(key, at: 0, effectiveRange: .none)
    }

    func _setAttribute(key: NSAttributedString.Key, value: Any) {
        let attributedString: NSMutableAttributedString!
        if let currentAttrString = attributedText {
            attributedString = NSMutableAttributedString(attributedString: currentAttrString)
        } else {
            attributedString = NSMutableAttributedString(string: text ?? "")
            text = nil
        } 
        attributedString.addAttribute(key,
                                      value: value,
                                      range: NSRange(location: 0, length: attributedString.length))
        attributedText = attributedString
    }
}

笔记:

  • 我不喜欢线高倍数。我的设计文档包含一个高度,比如 20,而不是倍数。
  • lineSpacing 与其他一些答案完全不同。不是你想要的。
  • 那里有一个额外的 _set/_getAttribute 方法的原因是我使用相同的方法来设置字母间距。也可以用于任何其他 NSAttributedString 值,但似乎我只使用字母间距(Swift/UIKit 中的字距调整)和行高。
于 2019-06-25T13:05:00.827 回答
2

有两个属性NSParagraphStyle可以修改同一段落中连续文本基线之间的高度:lineSpacinglineHeightMultiple。@Schoob 是正确的,a lineHeightMultipleabove在文本上方1.0添加了额外的空间,而 a lineSpacingabove0.0在文本下方添加了空间。该图显示了各个维度之间的关系。

因此,为了使文本保持居中,目标是根据另一个指定一个,这样我们通过一个属性(顶部/底部)添加的任何“填充”通过确定另一个属性的填充(底部/顶部)匹配。换句话说,添加的任何额外空间都会均匀分布,同时保留文本的现有位置。

好消息是,通过这种方式,您可以选择要指定的属性,然后确定另一个:

extension UIFont
{
    func lineSpacingToMatch(lineHeightMultiple: CGFloat) -> CGFloat {
        return self.lineHeight * (lineHeightMultiple - 1)
    }

    func lineHeightMultipleToMatch(lineSpacing: CGFloat) -> CGFloat {
        return 1 + lineSpacing / self.lineHeight
    }
}

从这里开始,其他答案显示了如何在 an 中设置这两个属性NSAttributedString,但这应该回答这两个属性如何与文本“居中”相关。

于 2018-07-18T18:45:28.997 回答
0

这在 Xcode 7.2 中对我有用。iOS 9.2.1。(斯威夫特 2.1。):

  dispatch_async(dispatch_get_main_queue()) { () -> Void in
        let paragraphStyleWithSpacing           = NSMutableParagraphStyle()
        paragraphStyleWithSpacing.lineSpacing   = 2.0 //CGFloat
        let textWithLineSpacing                 = NSAttributedString(string: str, attributes: [NSParagraphStyleAttributeName : paragraphStyleWithSpacing])
        self.MY_TEXT_VIEW_NAME.attributedText   = textWithLineSpacing
    }
于 2016-02-12T09:13:29.670 回答
0

使用 NSAttributedString 行位置的另一种方法是使用 baselineOffset属性:

let contentText = NSMutableAttributedString(
string: "I see\nI'd think it`d be both a notification and a\nplace to see past announcements\nLike a one way chat.")

contentText.addAttribute(.baselineOffset, value: 10, range: NSRange(location: 0, length: 5))
contentText.addAttribute(.baselineOffset, value: -10, range: NSRange(location: 85, length: 20))


结果:

“我知道

我认为它既是一个通知,也是一个
查看过去公告的地方,

就像单向聊天一样。”

https://stackoverflow.com/a/55876401/4683601

于 2019-04-27T01:04:37.300 回答
0

斯威夫特 4 & 5

extension NSAttributedString {

    /// Returns a new instance of NSAttributedString with same contents and attributes with line spacing added.
     /// - Parameter spacing: value for spacing you want to assign to the text.
     /// - Returns: a new instance of NSAttributedString with given line spacing.
     func withLineSpacing(_ spacing: CGFloat) -> NSAttributedString {
         let attributedString = NSMutableAttributedString(attributedString: self)
         let paragraphStyle = NSMutableParagraphStyle()
         paragraphStyle.lineBreakMode = .byTruncatingTail
         paragraphStyle.lineSpacing = spacing
         attributedString.addAttribute(.paragraphStyle,
                                       value: paragraphStyle,
                                       range: NSRange(location: 0, length: string.count))
         return NSAttributedString(attributedString: attributedString)
     }
}
于 2020-05-10T07:26:11.537 回答