Consider I have the following text in a UILabel
(a long line of dynamic text):
Since the alien army vastly outnumbers the team, players must use the post-apocalyptic world to their advantage, such as seeking cover behind dumpsters, pillars, cars, rubble, and other objects.
I want to resize the UILabel's
height so that the text can fit in. I'm using following properties of UILabel
to make the text within to wrap.
myUILabel.lineBreakMode = UILineBreakModeWordWrap;
myUILabel.numberOfLines = 0;
Please let me know if I'm not heading in the right direction. Thanks.
This question is related to
ios
cocoa-touch
uikit
uilabel
Since sizeWithFont is deprecated I use this one instead.
this one get label specific attributes.
-(CGFloat)heightForLabel:(UILabel *)label withText:(NSString *)text{
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName:label.font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){label.frame.size.width, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return ceil(rect.size.height);
}
myLabel.text = "your very long text"
myLabel.numberOfLines = 0
myLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
Please set constraints for UILable in storyboard including top left bottom right
Instead doing this programmatically, you can do this in Storyboard/XIB while designing.
Updated Method
+ (CGFloat)heightForText:(NSString*)text font:(UIFont*)font withinWidth:(CGFloat)width {
CGSize constraint = CGSizeMake(width, 20000.0f);
CGSize size;
CGSize boundingBox = [text boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:font}
context:nil].size;
size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
return size.height;
}
One line is Chris's answer is wrong.
newFrame.size.height = maximumLabelSize.height;
should be
newFrame.size.height = expectedLabelSize.height;
Other than that, it's the correct solution.
Instead doing this programmatically, you can do this in Storyboard/XIB while designing.
Swift 2:
yourLabel.text = "your very long text"
yourLabel.numberOfLines = 0
yourLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
yourLabel.frame.size.width = 200
yourLabel.frame.size.height = CGFloat(MAXFLOAT)
yourLabel.sizeToFit()
The interesting lines are sizeToFit()
in conjunction with setting a frame.size.height
to the max float, this will give room for long text, but sizeToFit()
will force it to only use the necessary, but ALWAYS call it after setting the .frame.size.height
.
I recommend setting a .backgroundColor
for debug purposes, this way you can see the frame being rendered for each case.
My approach to compute the dynamic height of UILabel.
let width = ... //< width of this label
let text = ... //< display content
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.preferredMaxLayoutWidth = width
// Font of this label.
//label.font = UIFont.systemFont(ofSize: 17.0)
// Compute intrinsicContentSize based on font, and preferredMaxLayoutWidth
label.invalidateIntrinsicContentSize()
// Destination height
let height = label.intrinsicContentSize.height
Wrap to function:
func computeHeight(text: String, width: CGFloat) -> CGFloat {
// A dummy label in order to compute dynamic height.
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.font = UIFont.systemFont(ofSize: 17.0)
label.preferredMaxLayoutWidth = width
label.text = text
label.invalidateIntrinsicContentSize()
let height = label.intrinsicContentSize.height
return height
}
UILabel extension based on this answer for Swift 4 and above
extension UILabel {
func retrieveTextHeight () -> CGFloat {
let attributedText = NSAttributedString(string: self.text!, attributes: [NSFontAttributeName:self.font])
let rect = attributedText.boundingRect(with: CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)
return ceil(rect.size.height)
}
}
Can be used like:
self.labelHeightConstraint.constant = self.label.retrieveTextHeight()
NSString *str = @"Please enter your text......";
CGSize lblSize = [str sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize: CGSizeMake(200.0f, 600.0f) lineBreakMode: NSLineBreakByWordWrapping];
UILabel *label = [[UILabel alloc]init];
label.frame = CGRectMake(60, 20, 200, lblSize.height);
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
label.font = [UIFont systemFontOfSize:15];
label.text = str;
label.backgroundColor = [UIColor clearColor];
[label sizeToFit];
[self.view addSubview:label];
You can implement TableViewController's
(UITableViewCell *)tableView:cellForRowAtIndexPath
method in the following way (for example) :
#define CELL_LABEL_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text = @"my long text";
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier] autorelease];
}
CGFloat width = [UIScreen mainScreen].bounds.size.width - 50;
CGFloat height = [self textHeight:text] + 10;
CGRect frame = CGRectMake(10.0f, 10.0f, width, height);
UILabel *cellLabel = [[UILabel alloc] initWithFrame:frame];
cellLabel.tag = CELL_LABEL_TAG;
cellLabel.textColor = [UIColor blackColor];
cellLabel.backgroundColor = [UIColor clearColor];
cellLabel.textAlignment = UITextAlignmentLeft;
cellLabel.font = [UIFont systemFontOfSize:12.0f];
[cell.contentView addSubview:cellLabel];
[cellLabel release];
return cell;
}
UILabel *label = (UILabel *)[cell viewWithTag:CELL_LABEL_TAG];
label.text = text;
label.numberOfLines = 0;
[label sizeToFit];
return cell;
Also use NSString
's sizeWithFont:constrainedToSize:lineBreakMode:
method to compute the text's height.
In iOS 6 Apple has added a property to UILabel that greatly simplifies dynamic vertical resizing of labels: preferredMaxLayoutWidth.
Using this property in combination with lineBreakMode = NSLineBreakByWordWrapping and sizeToFit method allows easily resize a UILabel instance to the height that accommodates the entire text.
A quote from iOS documentation:
preferredMaxLayoutWidth The preferred maximum width (in points) for a multiline label.
Discussion This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text is flowed to one or more new lines, thereby increasing the height of the label.
A sample:
...
UILabel *status = [[UILabel alloc] init];
status.lineBreakMode = NSLineBreakByWordWrapping;
status.numberOfLines = 5; // limits to 5 lines; use 0 for unlimited.
[self addSubview:status]; // self here is the parent view
status.preferredMaxLayoutWidth = self.frame.size.width; // assumes the parent view has its frame already set.
status.text = @"Some quite lengthy message may go here…";
[status sizeToFit];
[status setNeedsDisplay];
...
Problem is that none of mentioned functions is realiable and for some string and font will return incorrect height value. Especially will fail for attributed texts.
The only realiable solution is here: https://stackoverflow.com/a/4214978/699944 and the point is to use CoreText to manually calculate height of every line to get right size. There is no other known way to do this.
Here is a category version:
UILabel+AutoSize.h #import
@interface UILabel (AutoSize)
- (void) autosizeForWidth: (int) width;
@end
UILabel+AutoSize.m
#import "UILabel+AutoSize.h"
@implementation UILabel (AutoSize)
- (void) autosizeForWidth: (int) width {
self.lineBreakMode = UILineBreakModeWordWrap;
self.numberOfLines = 0;
CGSize maximumLabelSize = CGSizeMake(width, FLT_MAX);
CGSize expectedLabelSize = [self.text sizeWithFont:self.font constrainedToSize:maximumLabelSize lineBreakMode:self.lineBreakMode];
CGRect newFrame = self.frame;
newFrame.size.height = expectedLabelSize.height;
self.frame = newFrame;
}
@end
And for those that are migrating to iOS 8, here is a class extension for Swift:
extension UILabel {
func autoresize() {
if let textNSString: NSString = self.text {
let rect = textNSString.boundingRectWithSize(CGSizeMake(self.frame.size.width, CGFloat.max),
options: NSStringDrawingOptions.UsesLineFragmentOrigin,
attributes: [NSFontAttributeName: self.font],
context: nil)
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, rect.height)
}
}
}
You were going in the right direction. All you need to do is:
myUILabel.numberOfLines = 0;
myUILabel.text = @"Enter large amount of text here";
[myUILabel sizeToFit];
You can implement TableViewController's
(UITableViewCell *)tableView:cellForRowAtIndexPath
method in the following way (for example) :
#define CELL_LABEL_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text = @"my long text";
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier] autorelease];
}
CGFloat width = [UIScreen mainScreen].bounds.size.width - 50;
CGFloat height = [self textHeight:text] + 10;
CGRect frame = CGRectMake(10.0f, 10.0f, width, height);
UILabel *cellLabel = [[UILabel alloc] initWithFrame:frame];
cellLabel.tag = CELL_LABEL_TAG;
cellLabel.textColor = [UIColor blackColor];
cellLabel.backgroundColor = [UIColor clearColor];
cellLabel.textAlignment = UITextAlignmentLeft;
cellLabel.font = [UIFont systemFontOfSize:12.0f];
[cell.contentView addSubview:cellLabel];
[cellLabel release];
return cell;
}
UILabel *label = (UILabel *)[cell viewWithTag:CELL_LABEL_TAG];
label.text = text;
label.numberOfLines = 0;
[label sizeToFit];
return cell;
Also use NSString
's sizeWithFont:constrainedToSize:lineBreakMode:
method to compute the text's height.
This is one line of code to get the UILabel Height using Objective-c:
labelObj.numberOfLines = 0;
CGSize neededSize = [labelObj sizeThatFits:CGSizeMake(screenWidth, CGFLOAT_MAX)];
and using .height you will get the height of label as follows:
neededSize.height
You can implement TableViewController's
(UITableViewCell *)tableView:cellForRowAtIndexPath
method in the following way (for example) :
#define CELL_LABEL_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text = @"my long text";
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier] autorelease];
}
CGFloat width = [UIScreen mainScreen].bounds.size.width - 50;
CGFloat height = [self textHeight:text] + 10;
CGRect frame = CGRectMake(10.0f, 10.0f, width, height);
UILabel *cellLabel = [[UILabel alloc] initWithFrame:frame];
cellLabel.tag = CELL_LABEL_TAG;
cellLabel.textColor = [UIColor blackColor];
cellLabel.backgroundColor = [UIColor clearColor];
cellLabel.textAlignment = UITextAlignmentLeft;
cellLabel.font = [UIFont systemFontOfSize:12.0f];
[cell.contentView addSubview:cellLabel];
[cellLabel release];
return cell;
}
UILabel *label = (UILabel *)[cell viewWithTag:CELL_LABEL_TAG];
label.text = text;
label.numberOfLines = 0;
[label sizeToFit];
return cell;
Also use NSString
's sizeWithFont:constrainedToSize:lineBreakMode:
method to compute the text's height.
This method will give perfect height
-(float) getHeightForText:(NSString*) text withFont:(UIFont*) font andWidth:(float) width{
CGSize constraint = CGSizeMake(width , 20000.0f);
CGSize title_size;
float totalHeight;
title_size = [text boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{ NSFontAttributeName : font }
context:nil].size;
totalHeight = ceil(title_size.height);
CGFloat height = MAX(totalHeight, 40.0f);
return height;
}
Check this work perfectly without adding Single line of code. (Using Autolayout)
I made a demo for you according to your requirement. Download it from below link,
Step by Step Guide :-
Step 1 :- Set constrain to UIView
1) Leading 2) Top 3) Trailing (From mainview)
Step 2 :- Set constrain to Label 1
1) Leading 2) Top 3) Trailing (From it's superview)
Step 3 :- Set constrain to Label 2
1) Leading 2) Trailing (From it's superview)
Step 4 :- Most tricky give botton to UILabel from UIView .
Step 5 :- (Optional) Set constrain to UIButton
1) Leading 2) Bottom 3) Trailing 4) Fixed Height (From mainview)
Output :-
Note :- Make sure you have set Number of lines =0 in Label property.
I hope this info enough to understand Autoresize UIView according to UILabel's height and Autoresize UILabel According to text.
Finally, it worked. Thank you guys.
I was not getting it to work because i was trying to resize the label in heightForRowAtIndexPath
method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
and (yeah silly me), i was resizing the label to default in cellForRowAtIndexPath
method - i was overlooking the code i had written earlier:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cellIdentifier = @"myCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell.myUILabel.lineBreakMode = UILineBreakModeWordWrap;
cell.myUILabel.numberOfLines = 0;
cell.myUILabel.text = @"Some very very very very long text....."
[cell.myUILabel.criterionDescriptionLabel sizeToFit];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
CGFloat rowHeight = cell.myUILabel.frame.size.height + 10;
return rowHeight;
}
And for those that are migrating to iOS 8, here is a class extension for Swift:
extension UILabel {
func autoresize() {
if let textNSString: NSString = self.text {
let rect = textNSString.boundingRectWithSize(CGSizeMake(self.frame.size.width, CGFloat.max),
options: NSStringDrawingOptions.UsesLineFragmentOrigin,
attributes: [NSFontAttributeName: self.font],
context: nil)
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, rect.height)
}
}
}
The easiest and better way that worked for me was to apply height constraint to label and set the priority to low, i.e., (250) in storyboard.
So you need not worry about calculating the height and width programmatically, thanks to storyboard.
Finally, it worked. Thank you guys.
I was not getting it to work because i was trying to resize the label in heightForRowAtIndexPath
method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
and (yeah silly me), i was resizing the label to default in cellForRowAtIndexPath
method - i was overlooking the code i had written earlier:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Updated Method
+ (CGFloat)heightForText:(NSString*)text font:(UIFont*)font withinWidth:(CGFloat)width {
CGSize constraint = CGSizeMake(width, 20000.0f);
CGSize size;
CGSize boundingBox = [text boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:font}
context:nil].size;
size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
return size.height;
}
Updates according iOS7
// If description are available for protocol
protocolDescriptionLabel.text = [dataDictionary objectForKey:@"description"];
[protocolDescriptionLabel sizeToFit];
[protocolDescriptionLabel setLineBreakMode:NSLineBreakByWordWrapping];
CGSize expectedLabelSize = [protocolDescriptionLabel
textRectForBounds:protocolDescriptionLabel.frame
limitedToNumberOfLines:protocolDescriptionLabel.numberOfLines].size;
NSLog(@"expectedLabelSize %f", expectedLabelSize.height);
//adjust the label the the new height.
CGRect newFrame = protocolDescriptionLabel.frame;
newFrame.size.height = expectedLabelSize.height;
protocolDescriptionLabel.frame = newFrame;
You can get height using below code
You have to pass
text 2. font 3. label width
func heightForLabel(text: String, font: UIFont, width: CGFloat) -> CGFloat {
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
Thanks guys for help, here is the code I tried which is working for me
UILabel *instructions = [[UILabel alloc]initWithFrame:CGRectMake(10, 225, 300, 180)];
NSString *text = @"First take clear picture and then try to zoom in to fit the ";
instructions.text = text;
instructions.textAlignment = UITextAlignmentCenter;
instructions.lineBreakMode = NSLineBreakByWordWrapping;
[instructions setTextColor:[UIColor grayColor]];
CGSize expectedLabelSize = [text sizeWithFont:instructions.font
constrainedToSize:instructions.frame.size
lineBreakMode:UILineBreakModeWordWrap];
CGRect newFrame = instructions.frame;
newFrame.size.height = expectedLabelSize.height;
instructions.frame = newFrame;
instructions.numberOfLines = 0;
[instructions sizeToFit];
[self addSubview:instructions];
Solution to iOS7 prior and iOS7 above
//
// UILabel+DynamicHeight.m
// For StackOverFlow
//
// Created by Vijay on 24/02/14.
// Copyright (c) 2014 http://Vijay-Apple-Dev.blogspot.com. All rights reserved.
//
#import <UIKit/UIKit.h>
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define iOS7_0 @"7.0"
@interface UILabel (DynamicHeight)
/*====================================================================*/
/* Calculate the size,bounds,frame of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel;
@end
//
// UILabel+DynamicHeight.m
// For StackOverFlow
//
// Created by Vijay on 24/02/14.
// Copyright (c) 2014 http://Vijay-Apple-Dev.blogspot.com. All rights reserved.
//
#import "UILabel+DynamicHeight.h"
@implementation UILabel (DynamicHeight)
/*====================================================================*/
/* Calculate the size,bounds,frame of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel{
NSAssert(self, @"UILabel was nil");
//Label text
NSString *aLabelTextString = [self text];
//Label font
UIFont *aLabelFont = [self font];
//Width of the Label
CGFloat aLabelSizeWidth = self.frame.size.width;
if (SYSTEM_VERSION_LESS_THAN(iOS7_0)) {
//version < 7.0
return [aLabelTextString sizeWithFont:aLabelFont
constrainedToSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping];
}
else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(iOS7_0)) {
//version >= 7.0
//Return the calculated size of the Label
return [aLabelTextString boundingRectWithSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{
NSFontAttributeName : aLabelFont
}
context:nil].size;
}
return [self bounds].size;
}
@end
Since sizeWithFont is deprecated I use this one instead.
this one get label specific attributes.
-(CGFloat)heightForLabel:(UILabel *)label withText:(NSString *)text{
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:@{NSFontAttributeName:label.font}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){label.frame.size.width, CGFLOAT_MAX}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return ceil(rect.size.height);
}
This is one line of code to get the UILabel Height using Objective-c:
labelObj.numberOfLines = 0;
CGSize neededSize = [labelObj sizeThatFits:CGSizeMake(screenWidth, CGFLOAT_MAX)];
and using .height you will get the height of label as follows:
neededSize.height
This method will work for both iOS 6 and 7
- (float)heightForLabelSize:(CGSize)maximumLabelSize Font:(UIFont *)font String:(NSString*)string {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:font forKey: NSFontAttributeName];
CGSize adjustedLabelSize = [string maximumLabelSize
options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin
attributes:stringAttributes context:nil].size;
return adjustedLabelSize.height;
}
else {
CGSize adjustedLabelSize = [string sizeWithFont:font constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping];
return adjustedLabelSize.height;
}
}
To do this in Swift3 following is the code:
let labelSizeWithFixedWith = CGSize(width: 300, height: CGFloat.greatestFiniteMagnitude)
let exactLabelsize = self.label.sizeThatFits(labelSizeWithFixedWith)
self.label.frame = CGRect(origin: CGPoint(x: 20, y: 20), size: exactLabelsize)
You can get height using below code
You have to pass
text 2. font 3. label width
func heightForLabel(text: String, font: UIFont, width: CGFloat) -> CGFloat {
let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.font = font
label.text = text
label.sizeToFit()
return label.frame.height
}
My approach to compute the dynamic height of UILabel.
let width = ... //< width of this label
let text = ... //< display content
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.preferredMaxLayoutWidth = width
// Font of this label.
//label.font = UIFont.systemFont(ofSize: 17.0)
// Compute intrinsicContentSize based on font, and preferredMaxLayoutWidth
label.invalidateIntrinsicContentSize()
// Destination height
let height = label.intrinsicContentSize.height
Wrap to function:
func computeHeight(text: String, width: CGFloat) -> CGFloat {
// A dummy label in order to compute dynamic height.
let label = UILabel()
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.font = UIFont.systemFont(ofSize: 17.0)
label.preferredMaxLayoutWidth = width
label.text = text
label.invalidateIntrinsicContentSize()
let height = label.intrinsicContentSize.height
return height
}
UILabel *itemTitle = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 10,100, 200.0f)];
itemTitle.text = @"aseruy56uiytitfesh";
itemTitle.adjustsFontSizeToFitWidth = NO;
itemTitle.autoresizingMask = UIViewAutoresizingFlexibleWidth;
itemTitle.font = [UIFont boldSystemFontOfSize:18.0];
itemTitle.textColor = [UIColor blackColor];
itemTitle.shadowColor = [UIColor whiteColor];
itemTitle.shadowOffset = CGSizeMake(0, 1);
itemTitle.backgroundColor = [UIColor blueColor];
itemTitle.lineBreakMode = UILineBreakModeWordWrap;
itemTitle.numberOfLines = 0;
[itemTitle sizeToFit];
[self.view addSubview:itemTitle];
use this here all the properties are used on the label and test it by increasing the text in the itemTitle.text as
itemTitle.text = @"diofgorigjveghnhkvjteinughntivugenvitugnvkejrfgnvkhv";
it will show the perfetc answer as you need
Finally, it worked. Thank you guys.
I was not getting it to work because i was trying to resize the label in heightForRowAtIndexPath
method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
and (yeah silly me), i was resizing the label to default in cellForRowAtIndexPath
method - i was overlooking the code i had written earlier:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
myLabel.text = "your very long text"
myLabel.numberOfLines = 0
myLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
Please set constraints for UILable in storyboard including top left bottom right
In iOS 6 Apple has added a property to UILabel that greatly simplifies dynamic vertical resizing of labels: preferredMaxLayoutWidth.
Using this property in combination with lineBreakMode = NSLineBreakByWordWrapping and sizeToFit method allows easily resize a UILabel instance to the height that accommodates the entire text.
A quote from iOS documentation:
preferredMaxLayoutWidth The preferred maximum width (in points) for a multiline label.
Discussion This property affects the size of the label when layout constraints are applied to it. During layout, if the text extends beyond the width specified by this property, the additional text is flowed to one or more new lines, thereby increasing the height of the label.
A sample:
...
UILabel *status = [[UILabel alloc] init];
status.lineBreakMode = NSLineBreakByWordWrapping;
status.numberOfLines = 5; // limits to 5 lines; use 0 for unlimited.
[self addSubview:status]; // self here is the parent view
status.preferredMaxLayoutWidth = self.frame.size.width; // assumes the parent view has its frame already set.
status.text = @"Some quite lengthy message may go here…";
[status sizeToFit];
[status setNeedsDisplay];
...
Thanks guys for help, here is the code I tried which is working for me
UILabel *instructions = [[UILabel alloc]initWithFrame:CGRectMake(10, 225, 300, 180)];
NSString *text = @"First take clear picture and then try to zoom in to fit the ";
instructions.text = text;
instructions.textAlignment = UITextAlignmentCenter;
instructions.lineBreakMode = NSLineBreakByWordWrapping;
[instructions setTextColor:[UIColor grayColor]];
CGSize expectedLabelSize = [text sizeWithFont:instructions.font
constrainedToSize:instructions.frame.size
lineBreakMode:UILineBreakModeWordWrap];
CGRect newFrame = instructions.frame;
newFrame.size.height = expectedLabelSize.height;
instructions.frame = newFrame;
instructions.numberOfLines = 0;
[instructions sizeToFit];
[self addSubview:instructions];
This method will give perfect height
-(float) getHeightForText:(NSString*) text withFont:(UIFont*) font andWidth:(float) width{
CGSize constraint = CGSizeMake(width , 20000.0f);
CGSize title_size;
float totalHeight;
title_size = [text boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{ NSFontAttributeName : font }
context:nil].size;
totalHeight = ceil(title_size.height);
CGFloat height = MAX(totalHeight, 40.0f);
return height;
}
My code:
UILabel *label = [[UILabel alloc] init];
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
label.text = text;
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize];
CGSize size = [label sizeThatFits:CGSizeMake(width, MAXFLOAT)];
float height = size.height;
label.frame = CGRectMake(x, y, width, height);
Problem is that none of mentioned functions is realiable and for some string and font will return incorrect height value. Especially will fail for attributed texts.
The only realiable solution is here: https://stackoverflow.com/a/4214978/699944 and the point is to use CoreText to manually calculate height of every line to get right size. There is no other known way to do this.
Check this work perfectly without adding Single line of code. (Using Autolayout)
I made a demo for you according to your requirement. Download it from below link,
Step by Step Guide :-
Step 1 :- Set constrain to UIView
1) Leading 2) Top 3) Trailing (From mainview)
Step 2 :- Set constrain to Label 1
1) Leading 2) Top 3) Trailing (From it's superview)
Step 3 :- Set constrain to Label 2
1) Leading 2) Trailing (From it's superview)
Step 4 :- Most tricky give botton to UILabel from UIView .
Step 5 :- (Optional) Set constrain to UIButton
1) Leading 2) Bottom 3) Trailing 4) Fixed Height (From mainview)
Output :-
Note :- Make sure you have set Number of lines =0 in Label property.
I hope this info enough to understand Autoresize UIView according to UILabel's height and Autoresize UILabel According to text.
Updates according iOS7
// If description are available for protocol
protocolDescriptionLabel.text = [dataDictionary objectForKey:@"description"];
[protocolDescriptionLabel sizeToFit];
[protocolDescriptionLabel setLineBreakMode:NSLineBreakByWordWrapping];
CGSize expectedLabelSize = [protocolDescriptionLabel
textRectForBounds:protocolDescriptionLabel.frame
limitedToNumberOfLines:protocolDescriptionLabel.numberOfLines].size;
NSLog(@"expectedLabelSize %f", expectedLabelSize.height);
//adjust the label the the new height.
CGRect newFrame = protocolDescriptionLabel.frame;
newFrame.size.height = expectedLabelSize.height;
protocolDescriptionLabel.frame = newFrame;
This method will work for both iOS 6 and 7
- (float)heightForLabelSize:(CGSize)maximumLabelSize Font:(UIFont *)font String:(NSString*)string {
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:font forKey: NSFontAttributeName];
CGSize adjustedLabelSize = [string maximumLabelSize
options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin
attributes:stringAttributes context:nil].size;
return adjustedLabelSize.height;
}
else {
CGSize adjustedLabelSize = [string sizeWithFont:font constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping];
return adjustedLabelSize.height;
}
}
My code:
UILabel *label = [[UILabel alloc] init];
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
label.text = text;
label.textAlignment = NSTextAlignmentCenter;
label.font = [UIFont fontWithName:_bodyTextFontFamily size:_bodyFontSize];
CGSize size = [label sizeThatFits:CGSizeMake(width, MAXFLOAT)];
float height = size.height;
label.frame = CGRectMake(x, y, width, height);
You can implement TableViewController's
(UITableViewCell *)tableView:cellForRowAtIndexPath
method in the following way (for example) :
#define CELL_LABEL_TAG 1
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text = @"my long text";
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:identifier] autorelease];
}
CGFloat width = [UIScreen mainScreen].bounds.size.width - 50;
CGFloat height = [self textHeight:text] + 10;
CGRect frame = CGRectMake(10.0f, 10.0f, width, height);
UILabel *cellLabel = [[UILabel alloc] initWithFrame:frame];
cellLabel.tag = CELL_LABEL_TAG;
cellLabel.textColor = [UIColor blackColor];
cellLabel.backgroundColor = [UIColor clearColor];
cellLabel.textAlignment = UITextAlignmentLeft;
cellLabel.font = [UIFont systemFontOfSize:12.0f];
[cell.contentView addSubview:cellLabel];
[cellLabel release];
return cell;
}
UILabel *label = (UILabel *)[cell viewWithTag:CELL_LABEL_TAG];
label.text = text;
label.numberOfLines = 0;
[label sizeToFit];
return cell;
Also use NSString
's sizeWithFont:constrainedToSize:lineBreakMode:
method to compute the text's height.
You may use it as a method, as well. @Pyjamasam is very much true so i am just making its method. It may be helpfull for some one else
-(CGRect)setDynamicHeightForLabel:(UILabel*)_lbl andMaxWidth:(float)_width{
CGSize maximumLabelSize = CGSizeMake(_width, FLT_MAX);
CGSize expectedLabelSize = [_lbl.text sizeWithFont:_lbl.font constrainedToSize:maximumLabelSize lineBreakMode:_lbl.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = _lbl.frame;
newFrame.size.height = expectedLabelSize.height;
return newFrame;
}
and just set it like this
label.frame = [self setDynamicHeightForLabel:label andMaxWidth:300.0];
When autoLayout is enabled the resizing doesn't work :)
NSString *str = @"Please enter your text......";
CGSize lblSize = [str sizeWithFont:[UIFont systemFontOfSize:15] constrainedToSize: CGSizeMake(200.0f, 600.0f) lineBreakMode: NSLineBreakByWordWrapping];
UILabel *label = [[UILabel alloc]init];
label.frame = CGRectMake(60, 20, 200, lblSize.height);
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByWordWrapping;
label.font = [UIFont systemFontOfSize:15];
label.text = str;
label.backgroundColor = [UIColor clearColor];
[label sizeToFit];
[self.view addSubview:label];
The easiest and better way that worked for me was to apply height constraint to label and set the priority to low, i.e., (250) in storyboard.
So you need not worry about calculating the height and width programmatically, thanks to storyboard.
Here is a category version:
UILabel+AutoSize.h #import
@interface UILabel (AutoSize)
- (void) autosizeForWidth: (int) width;
@end
UILabel+AutoSize.m
#import "UILabel+AutoSize.h"
@implementation UILabel (AutoSize)
- (void) autosizeForWidth: (int) width {
self.lineBreakMode = UILineBreakModeWordWrap;
self.numberOfLines = 0;
CGSize maximumLabelSize = CGSizeMake(width, FLT_MAX);
CGSize expectedLabelSize = [self.text sizeWithFont:self.font constrainedToSize:maximumLabelSize lineBreakMode:self.lineBreakMode];
CGRect newFrame = self.frame;
newFrame.size.height = expectedLabelSize.height;
self.frame = newFrame;
}
@end
UILabel extension based on this answer for Swift 4 and above
extension UILabel {
func retrieveTextHeight () -> CGFloat {
let attributedText = NSAttributedString(string: self.text!, attributes: [NSFontAttributeName:self.font])
let rect = attributedText.boundingRect(with: CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)
return ceil(rect.size.height)
}
}
Can be used like:
self.labelHeightConstraint.constant = self.label.retrieveTextHeight()
One line is Chris's answer is wrong.
newFrame.size.height = maximumLabelSize.height;
should be
newFrame.size.height = expectedLabelSize.height;
Other than that, it's the correct solution.
UILabel *itemTitle = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 10,100, 200.0f)];
itemTitle.text = @"aseruy56uiytitfesh";
itemTitle.adjustsFontSizeToFitWidth = NO;
itemTitle.autoresizingMask = UIViewAutoresizingFlexibleWidth;
itemTitle.font = [UIFont boldSystemFontOfSize:18.0];
itemTitle.textColor = [UIColor blackColor];
itemTitle.shadowColor = [UIColor whiteColor];
itemTitle.shadowOffset = CGSizeMake(0, 1);
itemTitle.backgroundColor = [UIColor blueColor];
itemTitle.lineBreakMode = UILineBreakModeWordWrap;
itemTitle.numberOfLines = 0;
[itemTitle sizeToFit];
[self.view addSubview:itemTitle];
use this here all the properties are used on the label and test it by increasing the text in the itemTitle.text as
itemTitle.text = @"diofgorigjveghnhkvjteinughntivugenvitugnvkejrfgnvkhv";
it will show the perfetc answer as you need
Thanks for this post. It helped me a great deal. In my case I am also editing the text in a separate view controller. I noticed that when I use:
[cell.contentView addSubview:cellLabel];
in the tableView:cellForRowAtIndexPath: method that the label view was continually rendered over the top of the previous view each time I edited the cell. The text became pixelated, and when something was deleted or changed, the previous version was visible under the new version. Here's how I solved the problem:
if ([[cell.contentView subviews] count] > 0) {
UIView *test = [[cell.contentView subviews] objectAtIndex:0];
[test removeFromSuperview];
}
[cell.contentView insertSubview:cellLabel atIndex:0];
No more weird layering. If there is a better way to handle this, Please let me know.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cellIdentifier = @"myCell";
cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell.myUILabel.lineBreakMode = UILineBreakModeWordWrap;
cell.myUILabel.numberOfLines = 0;
cell.myUILabel.text = @"Some very very very very long text....."
[cell.myUILabel.criterionDescriptionLabel sizeToFit];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
CGFloat rowHeight = cell.myUILabel.frame.size.height + 10;
return rowHeight;
}
You were going in the right direction. All you need to do is:
myUILabel.numberOfLines = 0;
myUILabel.text = @"Enter large amount of text here";
[myUILabel sizeToFit];
Swift 2:
yourLabel.text = "your very long text"
yourLabel.numberOfLines = 0
yourLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
yourLabel.frame.size.width = 200
yourLabel.frame.size.height = CGFloat(MAXFLOAT)
yourLabel.sizeToFit()
The interesting lines are sizeToFit()
in conjunction with setting a frame.size.height
to the max float, this will give room for long text, but sizeToFit()
will force it to only use the necessary, but ALWAYS call it after setting the .frame.size.height
.
I recommend setting a .backgroundColor
for debug purposes, this way you can see the frame being rendered for each case.
You may use it as a method, as well. @Pyjamasam is very much true so i am just making its method. It may be helpfull for some one else
-(CGRect)setDynamicHeightForLabel:(UILabel*)_lbl andMaxWidth:(float)_width{
CGSize maximumLabelSize = CGSizeMake(_width, FLT_MAX);
CGSize expectedLabelSize = [_lbl.text sizeWithFont:_lbl.font constrainedToSize:maximumLabelSize lineBreakMode:_lbl.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = _lbl.frame;
newFrame.size.height = expectedLabelSize.height;
return newFrame;
}
and just set it like this
label.frame = [self setDynamicHeightForLabel:label andMaxWidth:300.0];
When autoLayout is enabled the resizing doesn't work :)
To do this in Swift3 following is the code:
let labelSizeWithFixedWith = CGSize(width: 300, height: CGFloat.greatestFiniteMagnitude)
let exactLabelsize = self.label.sizeThatFits(labelSizeWithFixedWith)
self.label.frame = CGRect(origin: CGPoint(x: 20, y: 20), size: exactLabelsize)
Thanks for this post. It helped me a great deal. In my case I am also editing the text in a separate view controller. I noticed that when I use:
[cell.contentView addSubview:cellLabel];
in the tableView:cellForRowAtIndexPath: method that the label view was continually rendered over the top of the previous view each time I edited the cell. The text became pixelated, and when something was deleted or changed, the previous version was visible under the new version. Here's how I solved the problem:
if ([[cell.contentView subviews] count] > 0) {
UIView *test = [[cell.contentView subviews] objectAtIndex:0];
[test removeFromSuperview];
}
[cell.contentView insertSubview:cellLabel atIndex:0];
No more weird layering. If there is a better way to handle this, Please let me know.
Finally, it worked. Thank you guys.
I was not getting it to work because i was trying to resize the label in heightForRowAtIndexPath
method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
and (yeah silly me), i was resizing the label to default in cellForRowAtIndexPath
method - i was overlooking the code i had written earlier:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Solution to iOS7 prior and iOS7 above
//
// UILabel+DynamicHeight.m
// For StackOverFlow
//
// Created by Vijay on 24/02/14.
// Copyright (c) 2014 http://Vijay-Apple-Dev.blogspot.com. All rights reserved.
//
#import <UIKit/UIKit.h>
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define iOS7_0 @"7.0"
@interface UILabel (DynamicHeight)
/*====================================================================*/
/* Calculate the size,bounds,frame of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel;
@end
//
// UILabel+DynamicHeight.m
// For StackOverFlow
//
// Created by Vijay on 24/02/14.
// Copyright (c) 2014 http://Vijay-Apple-Dev.blogspot.com. All rights reserved.
//
#import "UILabel+DynamicHeight.h"
@implementation UILabel (DynamicHeight)
/*====================================================================*/
/* Calculate the size,bounds,frame of the Multi line Label */
/*====================================================================*/
/**
* Returns the size of the Label
*
* @param aLabel To be used to calculte the height
*
* @return size of the Label
*/
-(CGSize)sizeOfMultiLineLabel{
NSAssert(self, @"UILabel was nil");
//Label text
NSString *aLabelTextString = [self text];
//Label font
UIFont *aLabelFont = [self font];
//Width of the Label
CGFloat aLabelSizeWidth = self.frame.size.width;
if (SYSTEM_VERSION_LESS_THAN(iOS7_0)) {
//version < 7.0
return [aLabelTextString sizeWithFont:aLabelFont
constrainedToSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping];
}
else if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(iOS7_0)) {
//version >= 7.0
//Return the calculated size of the Label
return [aLabelTextString boundingRectWithSize:CGSizeMake(aLabelSizeWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{
NSFontAttributeName : aLabelFont
}
context:nil].size;
}
return [self bounds].size;
}
@end
Source: Stackoverflow.com