swiftuilabelcenternsattributedstringbaseline

Set NSAttributedString center vertically each line using baselineOffset


I want to set label's line height and I use minimumLineHeight and maximumLineHeight of NSMutableParagraphStyle

extension UILabel {
    func setTextWithLineHeight(text: String?, lineHeight: CGFloat) {
        if let text = text {
            let style = NSMutableParagraphStyle()
            style.maximumLineHeight = lineHeight
            style.minimumLineHeight = lineHeight
            
            let attributes: [NSAttributedString.Key: Any] = [
                .paragraphStyle: style
                .baselineOffset: (lineHeight - font.lineHeight) / 4 // added!!️️🤟
            ]
                
            let attrString = NSAttributedString(string: text,
                                                attributes: attributes)
            self.attributedText = attrString
        }
    }
}

I add .baselineOffset attribute based on a answer NSAttributedString text always sticks to bottom with big lineHeight , because without it, text is sticks to bottom like this.

image

What I want is set text center vertically so using baselineOffset, I solved the problem. However I wonder why it set baseOffline as (attributes.lineHeight - font.lineHeight) / 4 not (attributes.lineHeight - font.lineHeight) / 2


Solution

  • On iOS 17+, baselineOffset works as expected.

    For example, this code provides vertically centered text on the line.

    let label = UILabel()
    let lineHeight = 100.0
    let paragraphStyle = NSMutableParagraphStyle()
    paragraphStyle.minimumLineHeight = lineHeight
    paragraphStyle.maximumLineHeight = lineHeight
    let baselineOffset = (lineHeight - label.font.lineHeight) / 2.0
    label.attributedText = NSAttributedString(
        string: "Some text",
        attributes: [
            .paragraphStyle: paragraphStyle,
            .baselineOffset: baselineOffset
        ]
    )
    

    But on iOS 16 and lower, you have to divide the baseline offset twice: let baselineOffset = (lineHeight - label.font.lineHeight) / 4.0 to receive the same result.

    Be careful!