web-dev-qa-db-ja.com

コアテキスト-NSAttributedStringの行の高さは適切ですか?

Core Textの行間隔で完全に暗闇の中にいます。 NSAttributedStringを使用しており、次の属性を指定しています。-kCTFontAttributeName-kCTParagraphStyleAttributeName

これからCTFrameSetterが作成され、コンテキストに描画されます。

段落スタイル属性で、行の高さを指定します。

KCTParagraphStyleSpecifierLineHeightMultipleを使用すると、各行は、この高さの中央に表示されるテキストではなく、テキストの上部でパディングを受け取ります。

KCTParagraphStyleSpecifierLineSpacingを使用すると、テキストの下部にパディングが追加されます。

テキストが行の下部または上部にあるのではなく、その高さの中央にあるテキスト(グリフ)で指定された行の高さを達成するのを手伝ってください。

CTLineなどを明示的に作成する経路をたどらない限りこれは不可能ですか?

54
Schoob

私はまだ次の声明に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);

これが誰かを助けることを願っています。より関連性の高い情報が見つかったら、この回答を更新します。

12
Schoob

Objective-C

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

Swift 5

let strLength = myString.length()
var style = NSMutableParagraphStyle()
style.lineSpacing = 24
attString.addAttribute(.paragraphStyle, value: style, range: NSRange(location: 0, length: strLength))
97
Tieme

In Swift

    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]
8
Enrique

プログラムによってだけでなく、ストーリーボードから複数の行間隔と行の高さを設定/更新できます。

Interface Builderから:

enter image description here

プログラムで:

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

Swift

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
7
Krunal

これを拡張しました。以下を参照してください。拡張機能を使用すると、次のように行の高さを設定できます。

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のカーニング)と行の高さだけで良いようです。
2
n13

NSParagraphStyleには、連続するテキストベースライン間の高さを変更する2つのプロパティがあります同じ段落内lineSpacinglineHeightMultiple。 @SchoobはlineHeightMultiple1.0はテキストの上にスペースを追加し、lineSpacing0.0は、テキストの下にスペースを追加します。 この図 は、さまざまなディメンションがどのように関連しているかを示しています。

したがって、テキストを中央に配置するには、一方の属性(上/下)で追加する「パディング」が他方の属性のパディング(下/上)一致します。言い換えると、追加された余分なスペースは均等に分散され、テキストの既存の配置は維持されます。

良い点は、この方法で指定する属性を選択し、他の属性を決定できることです。

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

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

ここから、これらの2つの属性をNSAttributedStringに設定する方法が他の回答からわかりますが、この2つがテキストの「中心」にどのように関連するかを答えるべきです。

1
wardw

NSAttributedStringの行位置を使用した別の方法は、 baselineOffset attribute:で再生することです

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

0
Ely Dantas

これらすべての答えを試しましたが、実際に正確な行の高さを取得するには、通常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
...
0
Matej Ukmar

これは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
    }
0
MB_iOSDeveloper