Search code examples
iosswiftuikituilabel

Shouldn't UILabel sizeThatFits return a size smaller or equal to the given size, not bigger, for single line labels?


I have a single-line UILabel with the following configuration:

let label = UILabel()
label.text = "Lorem ipsum dolor sit amet"
label.numberOfLines = 1

When I call sizeThatFits(size) on this label with a small size width, the result is always a size with a bigger width.

let labelSize = label.sizeThatFits(CGSize(width: 30, height: UILabel.noIntrinsicMetric))
// labelSize.width > 30

Shouldn't sizeThatFits() return a size that is smaller or equal than the fitting size?

EDIT:

Neither of the suggested answers clarify this question.

Calling textRect(forBounds:limitedToNumberOfLines:) returns a zero width and systemLayoutSizeFitting() returns the same size as sizeThatFits(). There is no other workaround that can be used in any of the suggested answers.


Solution

  • The documentation says:

    The intrinsic content size for a label defaults to the size that displays the entirety of the content on a single line.

    The whole point of sizeThatFits(_:) is “tell me what size I need to show all of this text.” The width parameter is essentially ignored if numberOfLines is 1.

    The width supplied to sizeThatFits(_:) only comes into play when using numberOfLines of 0 (or greater than 1). In that scenario, sizeThatFits(_:) will now let us know the label’s height (and width) that will fit the text wrapped within the originally supplied width.

    I understand from your comments that you were expecting it to never return a value whose width that exceeded 30 even if numberOfLines is 1. Right or wrong, that simply is not how it works. If you want to clamp the width to not exceed 30, you would do this yourself:

    let label = UILabel()
    label.text = "Lorem ipsum dolor sit amet"
    label.numberOfLines = 1
    
    var size = label.sizeThatFits(CGSize(width: 30, height: UILabel.noIntrinsicMetric))
    size.width = min(size.width, 30)