我完全沉浸在Core Text的行距中。我正在使用NSAttributedString并在其上指定以下属性: - kCTFontAttributeName - kCTParagraphStyleAttributeName
从这里创建CTFrameSetter并将其绘制到上下文中。
在段落样式属性中,我想指定行的高度。
当我使用kCTParagraphStyleSpecifierLineHeightMultiple时,每行接收文本顶部的填充,而不是在此高度的中间显示的文本。
当我使用kCTParagraphStyleSpecifierLineSpacing时,填充将添加到文本的底部。
请帮助我达到指定的行高,文本(字形)位于该高度的中间,而不是位于行的底部或顶部的文本。
如果没有明确创建CTLine的路线等,这是不可能的?
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))
我对以下陈述仍然没有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*) ¶graphStyle, 3);
[attributedString addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)style range:NSMakeRange(0, [string length])];
CFRelease(style);
希望这有助于某人。当我发现更多相关信息时,我会更新这个答案。
在Swift 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]
您可以从故事板以及以编程方式设置/更新行间距和行高度倍数。
来自Interface Builder:
编程方式:
SWift 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
NSParagraphStyle
有两个属性可以修改同一段落中连续文本基线之间的高度:lineSpacing
和lineHeightMultiple
。 @Schoob是正确的,lineHeightMultiple
上方的1.0
在文本上方增加了额外的空间,而lineSpacing
上方的0.0
在文本下方增加了空间。 This diagram展示了各个维度的相关性。
为了使文本保持居中,因此目标是以另一种方式指定一个,以便通过确定另一个属性的填充来平衡我们通过一个属性(顶部/底部)添加的任何“填充”(底部/顶部)匹配。换句话说,添加的任何额外空间均匀分布,同时保留文本的现有位置。
好的方面是,通过这种方式,您可以选择要指定的属性,然后确定另一个:
extension UIFont
{
func lineSpacingToMatch(lineHeightMultiple: CGFloat) -> CGFloat {
return self.lineHeight * (lineHeightMultiple - 1)
}
func lineHeightMultipleToMatch(lineSpacing: CGFloat) -> CGFloat {
return 1 + lineSpacing / self.lineHeight
}
}
从这里,其他答案显示如何在NSAttributedString
中设置这两个属性,但这应该回答两者如何与文本的“中心”相关联。
这在Xcode 7.2中对我有用。 iOS 9.2.1。 (Swift 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
}
使用NSAttributedString线位置进行twerking的另一种方法是使用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))
结果:
“我知道了 我认为它既是通知又是通知 看到过去的公告的地方 就像单向聊天一样。“
我为此做了一个扩展,见下文。使用扩展名,您可以像这样设置行高:
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
}
}
笔记: