UILabel clipping italic (oblique) text at left and right edges of content ( iOS 6+)

Published

Problem:
UILabel may clip italic (oblique) characters and even scripts at the left and right edges. The following screenshot displays the issue. At the left edge, the descender of the ‘j’ is clipped; at the right edge, the ascender of the ‘l’ is clipped. I realize this is subtle, and not everyone is going to care (however, the issue gets worse with larger font sizes).

enter image description here

Here’s a less subtle example using Zapfino, size 22. Note the ‘j’ in jupiter looks almost like an ‘i’:

enter image description here

In the examples above, the background color of the label is orange, the text is left aligned, and the label maintains its intrinsic content size.

This is the default behavior of a UILabel and its been that way for multiple versions of iOS (so I’m not expecting a fix from Apple).

What I have tried:
Setting the label’s clipsToBounds property to NO does not resolve the issue. I’m also aware that I could set a fixed width constraint on the label to give the text more room at the trailing edge. However, a fixed width constraint would not give the ‘j’, in the example above, more room.

I’m going to answer my own question using a solution that leverages Auto Layout and the label’s alignmentRectInsets.

Source: Ios7 Questions

Published
Categorised as autolayout, ios, ios7, uilabel Tagged , , ,

Answers

Swift version of NonClippingLabel with fixed sizeThatFits method from bilobatum answer.

class NonClippingLabel: UILabel {

    let gutter: CGFloat = 4

    override func draw(_ rect: CGRect) {
        super.drawText(in: rect.insetBy(dx: gutter, dy: 0))
    }

    override var alignmentRectInsets: UIEdgeInsets {
        return .init(top: 0, left: gutter, bottom: 0, right: gutter)
    }

    override var intrinsicContentSize: CGSize {
        var size = super.intrinsicContentSize
        size.width += gutter * 2

        return size
    }

    override func sizeThatFits(_ size: CGSize) -> CGSize {
        let fixedSize = CGSize(width: size.width - 2 * gutter, height: size.height)
        let sizeWithoutGutter = super.sizeThatFits(fixedSize)

        return CGSize(width: sizeWithoutGutter.width + 2 * gutter,
                      height: sizeWithoutGutter.height)
    }

}

Mr. Buck Schmidt

Leave a Reply

Your email address will not be published. Required fields are marked *

Still Have Questions?


Our dedicated development team is here for you!

We can help you find answers to your question for as low as 5$.

Contact Us
faq