Reputation: 9703
I have a UILabel which displays text to basically fill the screen. The text can be from one letter up to many words.
private lazy var myLabel: UILabel = {
let label = UILabel()
label.textAlignment = .center
label.baselineAdjustment = .alignCenters
label.numberOfLines = 0
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.1
let font = UIFont(name: "Arial Rounded MT Bold", size: 400)!
label.font = font
return label
}()
it's constraints as such:
self.myLabel.translatesAutoresizingMaskIntoConstraints = false
let leadingConstraint = NSLayoutConstraint(item: self.myLabel, attribute: NSLayoutConstraint.Attribute.leading, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.myLabel.superview, attribute: NSLayoutConstraint.Attribute.leading, multiplier: 1, constant: 20)
let trailingConstraint = NSLayoutConstraint(item: self.myLabel, attribute: NSLayoutConstraint.Attribute.trailing, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.myLabel.superview, attribute: NSLayoutConstraint.Attribute.trailing, multiplier: 1, constant: -20)
let topConstraint = NSLayoutConstraint(item: self.myLabel, attribute: NSLayoutConstraint.Attribute.top, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.myLabel.superview, attribute: NSLayoutConstraint.Attribute.top, multiplier: 1, constant: 20)
let bottomConstraint = NSLayoutConstraint(item: self.myLabel, attribute: NSLayoutConstraint.Attribute.bottom, relatedBy: NSLayoutConstraint.Relation.equal, toItem: self.myLabel.superview, attribute: NSLayoutConstraint.Attribute.bottom, multiplier: 1, constant: -20)
NSLayoutConstraint.activate([leadingConstraint, trailingConstraint, topConstraint, bottomConstraint])
The label displays correctly in width. It adjusts width dynamically to match the content width. However in Height there is some clipping in certain cases. The easiest to see is just one W letter. It displays fine in width but is clipped in height.
Is there any way to have a UILabel adjust the font to fit both height and width using Swift 5?
Upvotes: 0
Views: 737
Reputation: 480
I always use this thanks to backslash-f:
import Foundation
import UIKit
class LabelWithAdaptiveTextHeight: UILabel {
override func layoutSubviews() {
super.layoutSubviews()
font = fontToFitHeight()
}
private func fontToFitHeight() -> UIFont {
var minFontSize: CGFloat = 18
var maxFontSize: CGFloat = 67
var fontSizeAverage: CGFloat = 0
var textAndLabelHeightDiff: CGFloat = 0
while (minFontSize <= maxFontSize) {
fontSizeAverage = minFontSize + (maxFontSize - minFontSize) / 2
guard (text?.count)! > 0 else {
break
}
if let labelText: NSString = text as NSString? {
let labelHeight = frame.size.height
let testStringHeight = labelText.size(
withAttributes: [NSAttributedString.Key.font: font.withSize(fontSizeAverage)]
).height
textAndLabelHeightDiff = labelHeight - testStringHeight
if (fontSizeAverage == minFontSize || fontSizeAverage == maxFontSize) {
if (textAndLabelHeightDiff < 0) {
return font.withSize(fontSizeAverage - 1)
}
return font.withSize(fontSizeAverage)
}
if (textAndLabelHeightDiff < 0) {
maxFontSize = fontSizeAverage - 1
} else if (textAndLabelHeightDiff > 0) {
minFontSize = fontSizeAverage + 1
} else {
return font.withSize(fontSizeAverage)
}
}
}
return font.withSize(fontSizeAverage)
}
}
Upvotes: 1