UILabel
text size calculation
Swift
iOS development
user interface

How to calculate UILabel width based on text length?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A UILabel does not size itself correctly from character count alone because rendered width depends on font, point size, line-breaking mode, and available height. The correct approach is to ask iOS how much space the text needs with the actual font and constraints you plan to use. Once you do that, the width calculation becomes predictable and works across different strings and fonts.

Use Text Measurement, Not Character Count

Two strings with the same number of characters can have very different widths in the same font. For example, WWWW is wider than iiii. That is why multiplying text length by an average character width is only a rough guess.

In UIKit, the usual measurement tool is boundingRect on NSString or String with attributes.

swift
1import UIKit
2
3func labelWidth(for text: String, font: UIFont) -> CGFloat {
4    let maxSize = CGSize(width: .greatestFiniteMagnitude, height: font.lineHeight)
5    let rect = (text as NSString).boundingRect(
6        with: maxSize,
7        options: [.usesLineFragmentOrigin, .usesFontLeading],
8        attributes: [.font: font],
9        context: nil
10    )
11    return ceil(rect.width)
12}
13
14print(labelWidth(for: "Hello", font: .systemFont(ofSize: 17)))

ceil is important because fractional widths can still clip text when converted back into layout coordinates.

Set the Label Frame from the Measured Width

Once you know the width, you can apply it to a label frame directly in frame-based layouts.

swift
1import UIKit
2
3let label = UILabel()
4label.font = .systemFont(ofSize: 17)
5label.text = "Dynamic text"
6
7let width = labelWidth(for: label.text ?? "", font: label.font)
8label.frame = CGRect(x: 20, y: 40, width: width, height: label.font.lineHeight)

This works well for custom drawing, badges, chips, or views that are not primarily Auto Layout driven.

Use sizeThatFits When the Label Already Exists

If you already have a configured label, sizeThatFits can be a convenient alternative because it measures the label using its own properties.

swift
1import UIKit
2
3let label = UILabel()
4label.font = .systemFont(ofSize: 17)
5label.text = "Status: Active"
6label.numberOfLines = 1
7
8let size = label.sizeThatFits(CGSize(width: .greatestFiniteMagnitude, height: .greatestFiniteMagnitude))
9print(size.width)

This is often simpler than rebuilding the attribute dictionary manually when the label is already configured.

Handle Multi-Line Labels Differently

If numberOfLines is greater than 1, width and height interact. In that case, you usually constrain one dimension and measure the other.

For example, if the maximum width is fixed and the label may wrap:

swift
1import UIKit
2
3func labelSize(for text: String, font: UIFont, maxWidth: CGFloat) -> CGSize {
4    let maxSize = CGSize(width: maxWidth, height: .greatestFiniteMagnitude)
5    let rect = (text as NSString).boundingRect(
6        with: maxSize,
7        options: [.usesLineFragmentOrigin, .usesFontLeading],
8        attributes: [.font: font],
9        context: nil
10    )
11    return CGSize(width: ceil(rect.width), height: ceil(rect.height))
12}

For single-line labels, width is the main concern. For wrapping labels, you usually measure both dimensions together.

Prefer Auto Layout When Layout Rules Are Dynamic

If the app already uses Auto Layout, manually calculating width is sometimes unnecessary. A label can be allowed to size itself through constraints and content hugging priorities. Manual measurement is still useful when:

  1. You need the width to build another view.
  2. You are doing custom collection or table layout math.
  3. You are drawing nonstandard UI components.

In those cases, measurement is part of layout. Otherwise, Auto Layout can often do the final sizing more cleanly.

Include Padding If the Label Sits in a Container

Many developers calculate the raw text width and then wonder why badges or pill-shaped views look cramped. The text width is only part of the final UI width. Add padding explicitly if the label sits inside a styled container.

swift
let textWidth = labelWidth(for: "New", font: .boldSystemFont(ofSize: 14))
let totalWidth = textWidth + 16  // 8 points of horizontal padding on each side

That small adjustment usually matters more visually than the text measurement itself.

Common Pitfalls

  • Estimating width from character count instead of measuring with the real font.
  • Forgetting to round up measured values and getting clipped text.
  • Measuring a single-line label with one font and displaying it with another.
  • Treating multi-line measurement as if width could be computed independently from height.
  • Calculating text width correctly but forgetting the padding required by the surrounding UI.

Summary

  • 'UILabel width should be based on rendered text metrics, not character count.'
  • 'boundingRect and sizeThatFits are the standard UIKit tools for measurement.'
  • Use the actual font and constraints that the label will use at runtime.
  • For multi-line labels, measure width and height together against a maximum width.
  • Add container padding separately because text width is not the same as final view width.

Course illustration
Course illustration

All Rights Reserved.