Основной текст - NSAttributedString высота строки сделано правильно?
Я в полном неведении с межстрочным интервалом в Core Text. Я использую NSAttributedString, и я указываю на него следующие атрибуты: - kCTFontAttributeName - kCTParagraphStyleAttributeName
Из этого CTFrameSetter создается и обращается к контексту.
В атрибуте стиля абзаца я бы хотел указать высоту линий.
Когда я использую kCTParagraphStyleSpecifierLineHeightMultiple, каждая строка получает заполнение в верхней части текста вместо текста, отображаемого в середине этой высоты.
Когда я использую kCTParagraphStyleSpecifierLineSpacing, к нижней части текста добавляется отступ.
Пожалуйста, помогите мне достичь заданной высоты строки с текстом (глифами) в середине этой высоты вместо текста, расположенного внизу или вверху строки.
Разве это невозможно без перехода к явному созданию CTLine и т. Д.?
6 ответов
Я все еще не уверен на 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);
Надеюсь, это кому-нибудь поможет. Я обновлю этот ответ по мере того, как узнаю более актуальную информацию.
Вы можете использовать это, если вы разрабатываете для iOS >= 6.0
NSInteger strLength = [myString length];
NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
[style setLineSpacing:24];
[attString addAttribute:NSParagraphStyleAttributeName
value:style
range:NSMakeRange(0, strLength)];
В 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]
Вы можете установить / обновить межстрочный интервал и высоту строки, кратные из раскадровки, а также программно.
Из Интерфейсного Разработчика:
Программный:
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
Я попробовал все эти ответы, но чтобы действительно получить ТОЧНУЮ высоту строки, которая обычно содержится в файлах дизайна из 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
...
Я сделал расширение для этого, см. Ниже. С помощью расширения вы можете просто установить высоту строки следующим образом:
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) и высотой строки.
Swift 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)
}
}
Есть два свойства NSParagraphStyle
которые изменяют высоту между последовательными текстовыми базовыми линиями в том же абзаце: lineSpacing
а также lineHeightMultiple
, @Schoob прав, что lineHeightMultiple
выше 1.0
добавляет дополнительное пространство над текстом, а lineSpacing
выше 0.0
добавляет пространство под текстом. Эта диаграмма показывает, как связаны различные измерения.
Поэтому, чтобы текст оставался по центру, цель состоит в том, чтобы указать одно в терминах другого таким образом, чтобы любой "отступ", добавляемый одним атрибутом (верх / низ), был сбалансирован путем определения отступа другого атрибута (низ /). вверх), чтобы соответствовать. Другими словами, любое добавленное дополнительное пространство распределяется равномерно, в противном случае сохраняется существующее позиционирование текста.
Приятно, что таким образом вы можете выбрать, какой атрибут вы хотите указать, а затем просто определить другой:
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 - использование атрибута 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))
Результат:
"Я вижу
Я думаю, что это будет и уведомление, и
место, чтобы увидеть прошлые объявления
Как чат в одну сторону. "