Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong height for UILabel when using custom lineSpacing and kern

I am getting wrong height for an UILabel if I use NSAttributedString that has custom kern and lineSpacing.

Here is how I set the custom kern and line spacing:

override func viewDidLoad() {
    super.viewDidLoad()

    let shortText = "Single line"
    self.label.attributedText = self.getAttributedText(text: shortText, kern: 0.2, lineSpacing: 8)
    self.label2.attributedText = self.getAttributedText(text: shortText, kern: 0, lineSpacing: 8)
}

private func getAttributedText(text: String, kern: CGFloat, lineSpacing: CGFloat) -> NSAttributedString {
    let attributedString = NSMutableAttributedString(string: text)

    let style = NSMutableParagraphStyle()
    style.lineSpacing = lineSpacing

    let attributes: [NSAttributedStringKey : Any] =
        [.paragraphStyle : style,
         .kern: kern]

    attributedString.addAttributes(attributes,
                                   range: NSMakeRange(0, attributedString.length))

    return attributedString
}

And here is what I get:

Result

The first label (the one that has custom kern), has its height wrong. It's exactly 8 points taller than it should be - that's the custom line height that I am using.

This only happens for single line labels. If I use text that is on a couple of lines, it works as expected.

like image 843
itskoBits Avatar asked Feb 15 '18 15:02

itskoBits


1 Answers

This is a bug with NSAttributedStringKey.kern. As a workaround, you can calculate the number of lines of your UILabel with the suggestions in this answer. If it has one line only, set lineSpacing to 0.

private func getAttributedText(text: String, kern: CGFloat, lineSpacing: CGFloat) -> NSAttributedString {
    let attributedString = NSMutableAttributedString(string: text)

    let font = UIFont.systemFont(ofSize: 16)

    let attributes: [NSAttributedStringKey : Any] = [.kern: kern,
                                                     .font: font]

    attributedString.addAttributes(attributes, range: NSMakeRange(0, attributedString.length))

    let maxSize = CGSize(width: [custom width], height: CGFloat.greatestFiniteMagnitude)
    let sizeOfLabel = attributedString.boundingRect(with: maxSize, options: .usesLineFragmentOrigin, context: nil)

    if sizeOfLabel.height > font.lineHeight {
        let style = NSMutableParagraphStyle()
        style.lineSpacing = lineSpacing

        attributedString.addAttribute(.paragraphStyle, value: style, range: NSMakeRange(0, attributedString.length))
    }

    return attributedString
}
like image 164
Tamás Sengel Avatar answered Nov 15 '22 15:11

Tamás Sengel