Multiline UILabel with adjustsFontSizeToFitWidth
In this question, 0x90 provides a solution that - although a bit ugly - does what I want. Specifically, it deals correctly with the situation that a single word does not fit the width at the initial font size. I've slightly modified the code so that it works as a category on NSString
:
- (CGFloat)fontSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size {
CGFloat fontSize = [font pointSize];
CGFloat height = [self sizeWithFont:font constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height;
UIFont *newFont = font;
//Reduce font size while too large, break if no height (empty string)
while (height > size.height && height != 0) {
fontSize--;
newFont = [UIFont fontWithName:font.fontName size:fontSize];
height = [self sizeWithFont:newFont constrainedToSize:CGSizeMake(size.width,FLT_MAX) lineBreakMode:UILineBreakModeWordWrap].height;
};
// Loop through words in string and resize to fit
for (NSString *word in [self componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) {
CGFloat width = [word sizeWithFont:newFont].width;
while (width > size.width && width != 0) {
fontSize--;
newFont = [UIFont fontWithName:font.fontName size:fontSize];
width = [word sizeWithFont:newFont].width;
}
}
return fontSize;
}
To use it with a UILabel
:
CGFloat fontSize = [label.text fontSizeWithFont:[UIFont boldSystemFontOfSize:15] constrainedToSize:label.frame.size];
label.font = [UIFont boldSystemFontOfSize:fontSize];
EDIT: Fixed the code to initialize newFont
with font
. Fixes a crash under certain circumstances.
Autoresize multiline UILabel in Swift
Below code will keep the frame size
and adjust the font size
according with direction label content
.
let backgroundView = UIView(frame: CGRect(x: 5, y: UINavigationController().navigationBar.frame.height + UIApplication.shared.statusBarFrame.height, width: UIScreen.main.bounds.width - 10, height: UIScreen.main.bounds.width - 100))
let direction = UILabel()
override func viewDidLoad() {
super.viewDidLoad()
direction.backgroundColor = UIColor.green
direction.numberOfLines = 0
direction.textAlignment = .center
direction.font = UIFont.boldSystemFont(ofSize: 40)
direction.adjustsFontForContentSizeCategory = true
direction.adjustsFontSizeToFitWidth = true
direction.text = "This is some multiline label with a background colour" // Set or Initiate random function for your array here.
backgroundView.backgroundColor = UIColor.red
view.addSubview(backgroundView)
backgroundView.addSubview(direction)
Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(random), userInfo: nil, repeats: true)
direction.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint(item: direction,
attribute: .leading,
relatedBy: .equal,
toItem: backgroundView,
attribute: .leadingMargin,
multiplier: 1.0,
constant: 0.0).isActive = true
NSLayoutConstraint(item: direction,
attribute: .trailing,
relatedBy: .equal,
toItem: backgroundView,
attribute: .trailingMargin,
multiplier: 1.0,
constant: 0.0).isActive = true
NSLayoutConstraint(item: direction,
attribute: .top,
relatedBy: .equal,
toItem: backgroundView,
attribute: .topMargin,
multiplier: 1.0,
constant: 0.0).isActive = true
NSLayoutConstraint(item: direction,
attribute: .bottom,
relatedBy: .equal,
toItem: backgroundView,
attribute: .bottomMargin,
multiplier: 1.0,
constant: 0.0).isActive = true
}
func random(sender: Timer) {
//Place your random func code here.
}
Output:
Multiline UILabel with right-to-left text and auto adjusted font size
Don't set a specific height because of that is not expanding to your amount of text.
Steps 1 - Set top, leading, trailing and height constraint and change height relation to Greater Than or Equal to
Step 2 - label.numberOfLines = 0
Step 3 - label.sizeToFit()
step 4 - label.lineBreakMode = .byTruncatingTail
adjustsFontSizeToFitWidth has different effect on UILabel than on UITextField
I think it's fair to say that .adjustsFontSizeToFitWidth = true
only "mostly" works.
It is also primarily for use with string width.
Also, UILabel
and UITextField
do not use the same font rendering, and do not have the same bounding-box (text fields have an inset).
If you want both elements to have the same visual behaviors, your best bet is to use a UITextField
with user interaction disabled instead of a UILabel
.
Autoshrink on a UILabel with multiple lines
These people found a solution:
http://www.11pixel.com/blog/28/resize-multi-line-text-to-fit-uilabel-on-iphone/
Their solution is as follows:
int maxDesiredFontSize = 28;
int minFontSize = 10;
CGFloat labelWidth = 260.0f;
CGFloat labelRequiredHeight = 180.0f;
//Create a string with the text we want to display.
self.ourText = @"This is your variable-length string. Assign it any way you want!";
/* This is where we define the ideal font that the Label wants to use.
Use the font you want to use and the largest font size you want to use. */
UIFont *font = [UIFont fontWithName:@"Marker Felt" size:maxDesiredFontSize];
int i;
/* Time to calculate the needed font size.
This for loop starts at the largest font size, and decreases by two point sizes (i=i-2)
Until it either hits a size that will fit or hits the minimum size we want to allow (i > 10) */
for(i = maxDesiredFontSize; i > minFontSize; i=i-2)
{
// Set the new font size.
font = [font fontWithSize:i];
// You can log the size you're trying: NSLog(@"Trying size: %u", i);
/* This step is important: We make a constraint box
using only the fixed WIDTH of the UILabel. The height will
be checked later. */
CGSize constraintSize = CGSizeMake(labelWidth, MAXFLOAT);
// This step checks how tall the label would be with the desired font.
CGSize labelSize = [self.ourText sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
/* Here is where you use the height requirement!
Set the value in the if statement to the height of your UILabel
If the label fits into your required height, it will break the loop
and use that font size. */
if(labelSize.height <= labelRequiredHeight)
break;
}
// You can see what size the function is using by outputting: NSLog(@"Best size is: %u", i);
// Set the UILabel's font to the newly adjusted font.
msg.font = font;
// Put the text into the UILabel outlet variable.
msg.text = self.ourText;
In order to get this working, a IBOutlet must be assigned in the interface builder to the UILabel.
"IBOutlet UILabel *msg;"
All the merit is of the people at 11pixel.
Related Topics
How to Check Where My App Is Using Idfa
Uitextfield - Capture Return Button Event
How to Check If a Uialertcontroller Is Already Presenting
Service Workers and iOS/Safari
iOS 11 Core Nfc - Any Sample Code
Crashlytics iOS - Log Caught Exception
iOS 4.3 Hide Status Bar Permanently
App Submission Binary Does Not Show Up in Itunes Connect
Firebase for iOS, Googleservice-Info.Plist Property "Is_Analytics_Enabled" Set to "No"
How to Use Icloud to Sync the Nsuserdefaults Plist File
How to Use Cocoapods When Creating a Cocoa Touch Framework
Space Between Sections in Uitableview
Right Aligned Uitextfield Spacebar Does Not Advance Cursor in iOS 7
Xcframework with Pods Dependencies
Swift Failed with Exit Code 1 While Compiling in Xcode - Possibly Related to Bridging-Headers