I have a multiline UILabel whose font size I\'d like to adjust depending on the text length. The whole text should fit into the label\'s frame without truncating it.
//
// String+Utility.swift
//
// Created by Philip Engberg on 29/11/2018.
// Original code from http://stackoverflow.com/a/4383281/463892 & http://stackoverflow.com/a/18951386
//
import Foundation
import UIKit
extension String {
func fontSize(with font: UIFont, constrainedTo size: CGSize, minimumScaleFactor: CGFloat) -> CGFloat {
var fontSize = font.pointSize
let minimumFontSize = fontSize * minimumScaleFactor
var attributedText = NSAttributedString(string: self, attributes: [.font: font])
var height = attributedText.boundingRect(with: CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin], context: nil).size.height
var newFont = font
//Reduce font size while too large, break if no height (empty string)
while height > size.height && height != 0 && fontSize > minimumFontSize {
fontSize -= 1
newFont = UIFont(name: font.fontName, size: fontSize)!
attributedText = NSAttributedString(string: self, attributes: [.font: newFont])
height = attributedText.boundingRect(with: CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin], context: nil).size.height
}
// Loop through words in string and resize to fit
for word in self.components(separatedBy: NSCharacterSet.whitespacesAndNewlines) {
var width = word.size(withAttributes: [.font: newFont]).width
while width > size.width && width != 0 && fontSize > minimumFontSize {
fontSize -= 1
newFont = UIFont(name: font.fontName, size: fontSize)!
width = word.size(withAttributes: [.font: newFont]).width
}
}
return fontSize
}
}
Thought I would add my own take on the answer:
I think it's a slight improvement on some of the other answers because:
https://gist.github.com/chrisjrex/c571056a4b621f7099bcbd5e179f184f
Note: This solution should only be used when a UILabel has .numberOfLines = 0
and .lineBreakMode = .byWordWrapping
Otherwise you are better off using: .adjustFontSizeForWidth = true
from the standard swift library
The other answers on this thread were very helpful to me in coming up with my solution, thank you