I want to get the font size of some text after it's been scaled down in a UILabel or UITextField. This was possible before iOS 7.0: How to get UILabel (UITextView) auto adjusted font size?. However, sizeWithFont has been deprecated in iOS 7.0. I've tried using its replacement, sizeWithAttributes, but with no success. Is there any way to do this in iOS 7.0?
Swift 4
The answers above work well, but use some deprecated values/functions. Here's a fixed version that works in 2018.
func approximateAdjustedFontSizeWithLabel(_ label: UILabel) -> CGFloat {
var currentFont: UIFont = label.font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
currentFont = currentFont.withSize(currentFont.pointSize - 1.0)
currentSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
}
return currentFont.pointSize
}
Here's a function I made to get the adjusted font size of a UILabel:
Swift
func getApproximateAdjustedFontSizeWithLabel(label: UILabel) -> CGFloat {
if label.adjustsFontSizeToFitWidth == true {
var currentFont: UIFont = label.font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
currentSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
}
return currentFont.pointSize
}
else {
return label.font.pointSize
}
}
Objective-C
- (CGFloat)getApproximateAdjustedFontSizeWithLabel:(UILabel *)label {
if (label.adjustsFontSizeToFitWidth) {
UIFont *currentFont = label.font;
CGFloat originalFontSize = currentFont.pointSize;
CGSize currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];
while (currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor)) {
currentFont = [currentFont fontWithSize:currentFont.pointSize - 1];
currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];
}
return currentFont.pointSize;
}
else {
return label.font.pointSize;
}
}
I really liked @WaltersGE1's answer, so I made it into an extension for UILabel to make it even more convenient to use:
extension UILabel {
/// The receiver’s font size, including any adjustment made to fit to width. (read-only)
///
/// If `adjustsFontSizeToFitWidth` is not `true`, this is just an alias for
/// `.font.pointSize`. If it is `true`, it returns the adjusted font size.
///
/// Derived from: [https://mcmap.net/q/153224/-how-do-i-get-auto-adjusted-font-size-in-ios-7-0-or-later](https://mcmap.net/q/153224/-how-do-i-get-auto-adjusted-font-size-in-ios-7-0-or-later)
var fontSize: CGFloat {
get {
if adjustsFontSizeToFitWidth {
var currentFont: UIFont = font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
while currentSize.width > frame.size.width && currentFont.pointSize > (originalFontSize * minimumScaleFactor) {
currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
currentSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
}
return currentFont.pointSize
}
return font.pointSize
}
}
}
Swift 4
The answers above work well, but use some deprecated values/functions. Here's a fixed version that works in 2018.
func approximateAdjustedFontSizeWithLabel(_ label: UILabel) -> CGFloat {
var currentFont: UIFont = label.font
let originalFontSize = currentFont.pointSize
var currentSize: CGSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
currentFont = currentFont.withSize(currentFont.pointSize - 1.0)
currentSize = (label.text! as NSString).size(withAttributes: [NSAttributedStringKey.font: currentFont])
}
return currentFont.pointSize
}
Check after the text has been applied (perhaps force a view reload first) you can grab the font size. For instance with a UITextField, you could implement the delegate method for textDidChange and then find out the font size from the font attribute on the textField. For a label, you could update the text then check the font size.
Example I built a project which updated a UILabel from a UITextField
-(void)textFieldDidEndEditing:(UITextField *)textField{
self.label.text = textField.text;
CGSize initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
while ( initialSize.width > _label.frame.size.width ) {
[_label setFont:[_label.font fontWithSize:_label.font.pointSize - 1]];
initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
}
CGFloat actualSize = _label.font.pointSize;
NSLog(@"acutal size %f",actualSize );
}
The actualSize seems right. (size calculation source)
All the solutions so far assume integer font sizes and fail to respect UILabel
's minimumScaleFactor
property.
Something like this should work:
+ (CGFloat)fontSizeForLabel:(UILabel *)label
{
if (label.adjustsFontSizeToFitWidth == NO || label.minimumScaleFactor >= 1.f) {
// font adjustment is disabled
return label.font.pointSize;
}
CGSize unadjustedSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
CGFloat scaleFactor = label.frame.size.width / unadjustedSize.width;
if (scaleFactor >= 1.f) {
// the text already fits at full font size
return label.font.pointSize;
}
// Respect minimumScaleFactor
scaleFactor = MAX(scaleFactor, minimumScaleFactor);
CGFloat newFontSize = label.font.pointSize * scaleFactor;
// Uncomment this if you insist on integer font sizes
//newFontSize = floor(newFontSize);
return newFontSize;
}
© 2022 - 2024 — McMap. All rights reserved.