UILabel sizeThatFits too wide for 1-line label - ios

I have a label that I'm creating and displaying programmatically. It can be 1 or more lines. I want to the label to be truncated at the end if it's too long. When the label is > 1 line long the following code works fine. Create a blank project and drop this into viewDidLoad to play along at home. Any iOS or tvOS project should do.
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
label.numberOfLines = 2;
label.lineBreakMode = NSLineBreakByTruncatingTail;
label.backgroundColor = [UIColor blueColor];
[self.view addSubview:label];
NSDictionary *attributes = #{NSFontAttributeName:[UIFont systemFontOfSize:26.0]};
label.attributedText = [[NSAttributedString alloc] initWithString:#"The rain in Spain falls mainly on the plain." attributes:attributes];
CGSize maxLabelSize = CGSizeMake(200, CGFLOAT_MAX);
CGSize requiredSize = [label sizeThatFits:maxLabelSize];
NSLog(#"requiredSize: %#", NSStringFromCGSize(requiredSize));
label.frame = CGRectMake(50.0, 50.0, requiredSize.width, requiredSize.height);
However, if I change numberOfLines to 1 then sizeThatFits returns a size with a width wide enough to fit the entire string even though it's bigger than the width of maxLabelSize.
I can work around this by checking to see if requiredSize.width is greater than maxLabelSize.width, and adjusting appropriately, but I'd like to know why sizeThatFits behaves differently with a 1-line label than with a multi-line label. I would expect a size no greater than 200 with the height the same as the attributed string's line height.

I have no idea why sizeThatFits doesn't work, but another method textRectForBounds:limitedToNumberOfLines: does the trick. Something like
label.numberOfLines = 0;
CGSize requiredSize = [label textRectForBounds:CGRectMake(0, 0, 200, CGFLOAT_MAX) limitedToNumberOfLines:1].size;

UILabel * commlbl;
commlbl=[[UILabel alloc]initWithFrame:CGRectMake(10, commlbl1.bounds.size.height+50, commscroll.bounds.size.width-25, commscroll.bounds.size.height+70)];
[commlbl setFont:[UIFont fontWithName:#"OpenSans-Regular" size:16]];
[commlbl setTextColor:[UIColor whiteColor]];
[commlbl setTextAlignment:NSTextAlignmentCenter];
commlbl.lineBreakMode = NSLineBreakByWordWrapping;
commlbl.numberOfLines = 0;
commlbl.text = [USER_DFT GetUserDefault:#"msgString"];
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);
CGSize expectedLabelSize = [commlbl.text sizeWithFont:commlbl.font constrainedToSize:maximumLabelSize lineBreakMode:commlbl.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = commlbl.frame;
newFrame.size.height = expectedLabelSize.height;
commlbl.frame = newFrame;

Related

UIFont for Label not cooperating with size settings

I want to make a game title but I can't seem to make the font larger. Here's what I have. I opted to not use CGRectMake initializer setting because I wanted to just set the x and y positions, not the size of the label (which I presumed would've been dictated by the size: portion of the UIFont method below). The 100.0 is no different from size 40.0.
UILabel *title = [[UILabel alloc] init];
CGRect frame = title.frame;
frame.origin.y = 30;
frame.origin.x = 100;
title.frame= frame;
title.text = #"TWINSTONES";
title.backgroundColor = [UIColor clearColor];
title.font = [UIFont fontWithName:#"TWINSTONES" size:100.0];
[title setTextColor:[UIColor colorWithWhite:0.9 alpha:1.0]];
title.numberOfLines = 0;
[title sizeToFit];
[self.view addSubview:title];

boundingRectWithSize adds extra bottom padding to UILabel

UILabel is created like this:
label = [[UILabel alloc] initWithFrame:CGRectMake(32, 10, 268, 44)];
label.textAlignment = NSTextAlignmentLeft;
label.backgroundColor = [UIColor yellowColor];
label.numberOfLines = 2;
label.lineBreakMode = NSLineBreakByTruncatingTail;
Then to update the label I do this:
label.text = someText;
CGRect frame = label.frame;
NSDictionary *attributes = #{NSFontAttributeName: label.font};
CGRect rect = [someText boundingRectWithSize:CGSizeMake(label.frame.size.width, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
frame.size.height = rect.size.height;
label.frame = frame;
This works fine with the label only has one line of text, but I have a maximum of two lines. When the 2nd line gets truncated, extra bottom padding gets added to the label, which makes it impossible to position the label below it (the red label in the images):
Why does this happen? If it's a bug, is there a workaround?
Try something like this:
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:text attributes:attributes];
UILabel *anotherLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, myLabel.frame.size.width, MAXFLOAT)];
[anotherLabel setAttributedText:attrString];
[anotherLabel setNumberOfLines:2];
[anotherLabel setText:NSTextAlignmentLeft];
[anotherLabel setLineBreakMode:NSLineBreakByTruncatingTail];
[anotherLabel sizeToFit];
[myLabel setAttributedText:attrString];
[myLabel setFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, [anotherLabel frame].size.height)];

UILabel number of lines affecting the bounds size

I am having this peculiar behavior with UILabel. Any numberOfLines works ok, except 1. If I set the number of lines to 1 it ignores the width which I set later.
I don't understand why 1 line screws it up...
here is my code
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor greenColor];
label.text = #"here is my label with lots of text to fill, here is my label with lots of text to fill";
label.frame = CGRectMake(20, 20, 100, 0);
CGRect rect = label.frame;
label.numberOfLines = 2;
label.lineBreakMode = NSLineBreakByTruncatingTail;
[self.view addSubview:label];
rect.size.width = 100;
label.frame = rect;
[label sizeToFit];
Use this code:
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor greenColor];
label.text = #"here is my label with lots of text to fill, here is my label with lots of text to fill";
label.frame = CGRectMake(20, 20, 100, 0);
label.numberOfLines = 3;
label.lineBreakMode = NSLineBreakByTruncatingTail;
[self.view addSubview:label];
[label sizeToFit];
CGRect rect = label.frame;
rect.size.width = 100;
label.frame = rect;
With numberOfLines = 3:
With numberOfLines = 1:
If you wanna use numberOfLines = 1 in that case your text will be in one line.So please use numberOfLines = 0;
label.numberOfLines = 0;
And there is no need to again define label frame so please remove these statement.
CGRect rect = label.frame;
rect.size.width = 100;
label.frame = rect;
Use this code this is perfect..
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor greenColor];
label.text = #"here is my label with lots of text to fill, here is my label with lots of text to fill";
label.frame = CGRectMake(20, 20, 100, 0);
label.numberOfLines = 0;
label.lineBreakMode = NSLineBreakByTruncatingTail;
[self.view addSubview:label];
[label sizeToFit];
Yes, it doesn't work when numberOfLines=1
I have to add this line at the end to make it work for all cases..
label.width = min(label.width, 100)
Use this as :
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor greenColor];
label.text = #"here is my label with lots of text to fill, here is my label with lots of text to fill";
label.numberOfLines = 0;
CGSize labelSize = [label.text sizeWithFont:label.font constrainedToSize:CGSizeMake(100 , 9999) lineBreakMode:label.lineBreakMode];
float lHeight = labelSize.height;
label.frame = CGRectMake(20, 20, 100, lHeight);
label.lineBreakMode = NSLineBreakByTruncatingTail;
[self.view addSubview:label];
EDIT : - (void)sizeToFit
Description :
Resizes and moves the receiver view so it just encloses its subviews.
Call this method when you want to resize the current view so that it uses the most appropriate amount of space. Specific UIKit views resize themselves according to their own internal needs. In some cases, if a view does not have a superview, it may size itself to the screen bounds. Thus, if you want a given view to size itself to its parent view, you should add it to the parent view before calling this method.
// [label sizeToFit];
Hope it helps you.

ios Dynamic sizing labels

I've tried to search online, but haven't found a clear answer for my issue so I've come to ask for your expert advice. I have a view with 2 labels on it. The first label is used to show an abbreviation of a name, 2-3 letters. and the second label shows the full name.
The question that I have is if there was a way to dynamically size the label based on the font type, size, and string length given? I ask because I would like the second label close to the first without too much empty space between the two or without the first label overlapping the second.
The reason that this isn't all in one label is because the first label should have a bigger font and different color scheme then the second label.
Any advice is greatly appreciated.
You can calculate the size of in which your string will appear and then can set frame of your UILabel to that size see following code as a sample -
//Calculate the expected size based on the font and linebreak mode of your label
CGSize maximumLabelSize = CGSizeMake(296,9999);
CGSize expectedLabelSize = [yourString sizeWithFont:yourLabel.font
constrainedToSize:maximumLabelSize
lineBreakMode:yourLabel.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = yourLabel.frame;
newFrame.size.height = expectedLabelSize.height;
yourLabel.frame = newFrame;
Update -
Use sizeWithAttributes: instead, which now takes an NSDictionary. Pass in the pair with key UITextAttributeFont and your font object like this:
CGSize size = [string sizeWithAttributes:
#{NSFontAttributeName:
[UIFont systemFontOfSize:17.0f]}];
Check Replacement for deprecated sizeWithFont: in iOS 7? for more details
This will also do the trick and will take into account attributed text
label.attributedText = attrString;
CGSize maximumLabelSize = CGSizeMake(187,CGFLOAT_MAX);
CGSize requiredSize = [label sizeThatFits:maximumLabelSize];
CGRect labelFrame = label.frame;
labelFrame.size.height = requiredSize.height;
label.frame = labelFrame;
'sizeWithFont:' is deprecated: first deprecated in iOS 7.0.
so try sizeWithAttributes
- (void)viewDidLoad
{
[super viewDidLoad];
label = [[UILabel alloc] initWithFrame:CGRectMake(20, 40, 300, 20)];
label.backgroundColor = [UIColor blueColor];
const CGFloat fontSize = 30;
UIFont *regularFont = [UIFont systemFontOfSize:fontSize];
UIColor *foregroundColor = [UIColor blackColor];
attrs = [NSDictionary dictionaryWithObjectsAndKeys:
regularFont, NSFontAttributeName,
foregroundColor, NSForegroundColorAttributeName
, nil];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]
initWithString:#"Test Text"
attributes:attrs];
[label setAttributedText:attributedText];
[self.view addSubview:label];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGSize expectedLabelSize = [label.text sizeWithAttributes:attrs]; // iOS 7 Code <--
CGRect newFrame = label.frame;
newFrame.size.width = expectedLabelSize.width;
label.frame = newFrame;
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]
initWithString:#"Longer Test Text"
attributes:attrs];
[label setAttributedText:attributedText];
}
As sizeWithFont: is deprecated in iOS 7, you need to use sizeWithAttributes (as maver explained here). In order to simplify code, you can add a method that you can reuse like this:
-(CGRect)rectForText:(NSString *)text
usingFont:(UIFont *)font
boundedBySize:(CGSize)maxSize
{
NSAttributedString *attrString =
[[NSAttributedString alloc] initWithString:text
attributes:#{ NSFontAttributeName:font}];
return [attrString boundingRectWithSize:maxSize
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
}
And make use of it
CGSize maximumLabelSize = CGSizeMake(280,9999);
UIFont *font = [UIFont systemFontOfSize:20];
CGRect titleRect = [self rectForText:post.title // <- your text here
usingFont:font
boundedBySize:maximumLabelSize];
In addition of Saurabh's answer. I had the same problem and you should add this line [yourLabel setNumberOfLines:0]; in order the whole text to be shown in X lines.

UILabel with text constrainedToSize returns wrong height

I've read many questions on the topic but I can't seem to find what is wrong with my code:
UILabel *nameLabel = [[UILabel alloc] init];
[nameLabel setText: _nameString];
nameLabel.textAlignment = UITextAlignmentLeft;
nameLabel.contentMode = UIViewContentModeTop;
nameLabel.lineBreakMode = UILineBreakModeWordWrap;
nameLabel.numberOfLines = 0;
nameLabel.font = [UIFont fontWithName:#"Verdana" size:14];
nameLabel.backgroundColor = [UIColor clearColor];
nameLabel.textColor = [UIColor colorWithRed:0 green:0.282 blue:0.31 alpha:1];
nameLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
CGSize maximumLabelSize = CGSizeMake(200.0f, 60.0f);
CGSize expectedLabelSize = [_nameString sizeWithFont:nameLabel.font
constrainedToSize:maximumLabelSize
lineBreakMode:nameLabel.lineBreakMode];
nameLabel.frame = CGRectMake(10, 10, expectedLabelSize.width, expectedLabelSize.height);
And although sometimes it does work (on larger texts) on texts like "Airplanes being the future" the expectedLabelSize returns height 18.0f and it cuts the sentence on the "Airplanes being the"
What am I doing wrong here?
I had the same problem once, that was because my label's width was smaller than the maximum Label's width wat I used to calculate the "expectedLabelSize".
Since you are using an autoresizingMask your label might be too small.

Resources