Swift - Adjusting fontSize to fit the width of the layout (programmatically)
Try the following commands for your label:
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.2
And try to change the lines of the label to 0 and 1 (check both cases):
label.numberOfLines = 0 // or 1
MinimumScaleFactor
range is 0 to 1. So we are setting the MinimumScaleFactor
with respect to our font size as follows
Objective C
[lb setMinimumScaleFactor:10.0/[UIFont labelFontSize]];
lb.adjustsFontSizeToFitWidth = YES;
Swift 3.0
lb.minimumScaleFactor = 10/UIFont.labelFontSize
lb.adjustsFontSizeToFitWidth = true
I don't know if this will completely answer your question, but you can use this extension to calculate your own font sizes to fit.
Swift 3
extension String {
func height(constrainedBy width: CGFloat, with font: UIFont) -> CGFloat {
let constraintSize = CGSize(width: width, height: .max)
let boundingBox = self.boundingRectWithSize(constraintSize, options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return boundingBox.height
}
func width(constrainedBy height: CGFloat, with font: UIFont) -> CGFloat {
let constrainedSize = CGSize(width: .max, height: height)
let boundingBox = self.boundingRectWithSize(constrainedSize, options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return boundingBox.width
}
}
Update - Adds example and updates code to Swift 5
Swift 5
extension String {
func height(constrainedBy width: CGFloat, with font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)
return boundingBox.height
}
func width(constrainedBy height: CGFloat, with font: UIFont) -> CGFloat {
let constrainedRect = CGSize(width: .greatestFiniteMagnitude, height: height)
let boundingBox = self.boundingRect(with: constrainedRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font: font], context: nil)
return boundingBox.width
}
}
Here is my logic to make sure that two different labels had the same font size. In my case it was two labels for the user's first and last name. The reason I needed two labels for this, is because each label is independently animated.
class ViewController: UIViewController {
...
func viewDidLoad() {
super.viewDidLoad()
fixFontSizes()
...
}
func fixFontSizes() {
let leadingMargin = self.leadingContainerConstraint.constant
let trailingMargin = self.trailingContainerConstraint.constant
let maxLabelWidth = self.view.bounds.width - leadingMargin - trailingMargin
let firstName = self.firstNameLabel.text ?? ""
let lastName = self.lastNameLabel.text ?? ""
let firstNameWidth = firstName.width(constrainedBy: self.container.bounds.height, with: self.firstNameLabel.font)
let lastNameWidth = lastName.width(constrainedBy: self.container.bounds.height, with: self.lastNameLabel.font)
let largestLabelWidth = max(firstNameWidth, lastNameWidth)
guard largestLabelWidth > maxLabelWidth else { return }
let largestTextSize = max(self.firstNameLabel.font.pointSize, self.lastNameLabel.font.pointSize)
let labelToScreenWidthRatio = largestLabelWidth / maxLabelWidth
let calculatedMaxTextSize = floor(largestTextSize / labelToScreenWidthRatio)
self.firstNameLabel.font = self.firstNameLabel.font.withSize(calculatedMaxTextSize)
self.lastNameLabel.font = self.lastNameLabel.font.withSize(calculatedMaxTextSize)
}
}