NSAttributedString with baselineOffset can cause the last line to be cut off

Viewed 487

I’ve got an attributed string with a set baseline offset which renders as I’d expect.

enter image description here

The issue is when I add any other style (color, strikethrough, link, etc) to only part of the string, the text gets positioned wrong so that the last line isn’t rendered.

enter image description here

Is there a way to make this work properly?

My original goal was to change the line height to be smaller than the default of the font, then move the baseline so the tops of some characters wont be cut off (like $).


Here's the simplest version I could make to reproduce this in a playground.

import UIKit
​
let baselineOffset: Float = 5
​
let defaultAttributes: [NSAttributedString.Key: Any] = [
    .baselineOffset: NSNumber(value: baselineOffset),
]
​
let middleAttributes: [NSAttributedString.Key: Any] = [
    .foregroundColor: UIColor.blue,
//    .strikethroughStyle: NSNumber(value: NSUnderlineStyle.single.rawValue)
//    .link: URL(fileURLWithPath: ""),
]
​
let part = NSMutableAttributedString(string: "Lorem ipsum\n", attributes: defaultAttributes)
​
let middlePart = NSMutableAttributedString(attributedString: part)
middlePart.addAttributes(middleAttributes,
                          range: NSRange(location: 0, length: middlePart.length))
​
let string = NSMutableAttributedString()
string.append(part)
string.append(middlePart)
string.append(part)
​
// Remove last newline
string.replaceCharacters(in: NSRange(location: string.length-1, length: 1), with: "")
​
print(string)
​
let label = UILabel()
label.backgroundColor = .white
label.numberOfLines = 0
label.attributedText = string
label.sizeToFit()
label
2 Answers

You can add "Hair space" character (or any other almost invisible character) at the very beginning of the string.

string.append(part)
string.append(middlePart)
string.append(part)
string.insert(NSAttributedString(string: "\u{200A}"), at: 0)

The problem is that the baselineOffset value is greater than the text height, it's above or below the text size frame, depending on the value. Try to adjust the baselineOffset value.

Related