boundingRectWithSize gives height with truncated text - ios

I am using the following method to determine the height required to display the text that i have. However i cannot get the correct height without truncating the text at the end.
CGRect labelRect = [comment boundingRectWithSize:headerMax
options:NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:#{NSFontAttributeName:font}
context:nil];
How can i say not to determine the required label height without truncating the text at the end. I want the whole text to fit into the label.

-(CGRect)getLabelSizeWithText:(NSString *)textLabel forFontSize:(CGFloat) fontSize
{
CGRect textRect;
if (textLabel != nil)
{
NSAttributedString *actualString = [[NSAttributedString alloc] initWithString:textLabel attributes:#{NSFontAttributeName:[UIFont fontWithName:#"HelveticaNeue" size:fontSize]} ];
NSStringDrawingContext *targetContext = [[NSStringDrawingContext alloc] init];
CGFloat commentLabelWidth = [[UIScreen mainScreen]bounds].size.width;
textRect = [actualString boundingRectWithSize:CGSizeMake(commentLabelWidth, 900) options:NSStringDrawingUsesLineFragmentOrigin context:targetContext];
}
return textRect;
}
This one should work. Try it

Use -
1. If you want word wrap -
labelView.lineBreakMode = NSLineBreakByWordWrapping;
labelView.numberOfLines = 2;
CGRect labelRect = [comment boundingRectWithSize:headerMax
options:NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading | NSLineBreakByWordWrapping
attributes:#{NSFontAttributeName:font}
context:nil];
2. If you Don't want truncating tail at all -
// No line break mode
labelView.numberOfLines = 0;
CGRect labelRect = [comment boundingRectWithSize:headerMax
options:NSStringDrawingUsesLineFragmentOrigin |
NSStringDrawingUsesFontLeading
attributes:#{NSFontAttributeName:font}
context:nil];

Try this
 
NSString *cellText = restaurant.review;
UIFont *cellFont = [UIFont systemFontOfSize:14.0];
NSDictionary *attributes = #{NSFontAttributeName: cellFont};
CGRect labelSize = [cellText boundingRectWithSize:CGSizeMake([UIScreen mainScreen].bounds.size.width-20, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil];

I am not really sure whether I understood your question correctly; it sounds like you are trying to calculate the frame size needed to display the text and setting the frame manually with that. Additionally, by setting .numberOfLines = 2, you are limiting the text that you can show. My suggestion would be for you to set up constraints via autolayout, optionally add a .minimumScaleFactor and let it dynamically resize itself.
If you still want to calculate size, with numberOfLines taken into consideration, you can use a prototype label and have use its height
- (CGSize)preferredSizeForString:(NSString *)string
width:(CGFloat)width
{
UILabel *prototypelabel = [UILabel new];
prototypelabel.frame = CGRectMake(0, 0, width, 0);
prototypelabel.text = #"Your string";
prototypelabel.numberOfLines = 2;
[prototypelabel sizeToFit];
return prototypelabel.frame.size;
}

Related

SGABRT error on depricated code in iOS xcode [duplicate]

In iOS7, sizeWithFont is deprecated, so I am using boundingRectWithSize(which returns a CGRect value). My code:
UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
// you can use your font.
CGSize maximumLabelSize = CGSizeMake(310, 9999);
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:fontText}
context:nil];
expectedLabelSize = CGSizeMake(textRect.size.width, textRect.size.height);
In textRect, I'm getting a size greater than my maximumLabelSize, a different size than when using sizeWithFont. How can I resolve this issue?
How about create new label and using sizeThatFit:(CGSize)size ??
UILabel *gettingSizeLabel = [[UILabel alloc] init];
gettingSizeLabel.font = [UIFont fontWithName:#"YOUR FONT's NAME" size:16];
gettingSizeLabel.text = #"YOUR LABEL's TEXT";
gettingSizeLabel.numberOfLines = 0;
gettingSizeLabel.lineBreakMode = NSLineBreakByWordWrapping;
CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);
CGSize expectSize = [gettingSizeLabel sizeThatFits:maximumLabelSize];
Edit: This upper code is not good for ios 7 and above, so please use below:
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize
options:NSStringDrawingUsesLineFragmentOrigin| NSStringDrawingUsesFontLeading
attributes:#{NSFontAttributeName:fontText}
context:nil];
Maybe you need to provide additional option to the method that is suggested in this answer:
CGSize maximumLabelSize = CGSizeMake(310, CGFLOAT_MAX);
CGRect textRect = [myString boundingRectWithSize:maximumLabelSize
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName: fontText}
context:nil];
Here is my working code snippet:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithDictionary:attributeDict];
NSString *headline = [dict objectForKey:#"title"];
UIFont *font = [UIFont boldSystemFontOfSize:18];
CGRect rect = [headline boundingRectWithSize:CGSizeMake(300, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:#{NSFontAttributeName:font} context:nil];
CGFloat height = roundf(rect.size.height +4)
I added 4px to the calculated height, because without these 4px, there is one line missing.
I use this code snippet in a tableView and add the "height" to an array of NSNumbers and I get the correct cell height for the default textLabel.
Add 4 more pixel if you want more space under the text in the textLabel.
**** UPDATE ****
I do not agree with the "width bug of 40px", I shout be the 4px of missing height, because 4px is the default height of a space between a letter and the bound of a single line.
You can check it with a UILabel, for a fontsize of 16 you need a UILabel height of 20.
But if your last line has no "g" or whatever in it, the measuring could be miss the 4px of height.
I rechecked it with a little method, I get an accurate height of 20,40 or 60
for my label and a right width less than 300px.
To support iOS6 and iOS7, you can use my method:
- (CGFloat)heightFromString:(NSString*)text withFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
CGRect rect;
float iosVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if (iosVersion >= 7.0) {
rect = [text boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:#{NSFontAttributeName:font} context:nil];
}
else {
CGSize size = [text sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
rect = CGRectMake(0, 0, size.width, size.height);
}
NSLog(#"%#: W: %.f, H: %.f", self, rect.size.width, rect.size.height);
return rect.size.height;
}
**** UPGRADE ****
Thanks to your comments, I upgraded my function as followed. Since sizeWithFont is deprecated and you will get a warning in XCode, I added the diagnostic-pragma-code to remove the warning for this particular function-call/block of code.
- (CGFloat)heightFromStringWithFont:(UIFont*)font constraintToWidth:(CGFloat)width
{
CGRect rect;
if ([self respondsToSelector:#selector(boundingRectWithSize:options:attributes:context:)]) {
rect = [self boundingRectWithSize:CGSizeMake(width, 1000) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:#{NSFontAttributeName:font} context:nil];
}
else {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
CGSize size = [self sizeWithFont:font constrainedToSize:CGSizeMake(width, 1000) lineBreakMode:NSLineBreakByWordWrapping];
rect = CGRectMake(0, 0, size.width, size.height);
#pragma GCC diagnostic pop
}
return ceil(rect.size.height);
}
In addition to the 4px topic:
depending which font and font-weight you use, the calculation returns different height-values. In my case: HelveticaNeue-Medium with a fontsize of 16.0 returns a line-height of 20.0 for a single line but 39.0 for two lines, 78px for 4 lines --> 1px missing for every line - beginning with line 2 - but you want to have your fontsize + 4px linespace for every line you have to get a height-result.
Please keep that in mind while coding!
I don´t have a function yet for this "problem" but I will update this post when I´m finished.
If I understand correctly, you are using boundingRectWithSize: just as a way of getting the size you would get with sizeWithFont (meaning you want directly the CGSize, not the CGRect)?
This looks like what you are looking for :
Replacement for deprecated sizeWithFont: in iOS 7?
They are using sizeWithAttributes: to get the size, as a replacement for sizeWithFont.
Do you still get the wrong size using something like this :
UIFont *fontText = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
// you can use your font.
expectedLabelSize = [myString sizeWithAttributes:#{NSFontAttributeName:fontText}];
The #SoftDesigner's comment has worked for me
CGRect descriptionRect = [description boundingRectWithSize:CGSizeMake(width, 0)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName : [UIFont systemFontOfSize:12]}
context:nil];
result = ceil(descriptionRect.size.height);
for finding size of label run time sizewithfont is deprecated for iOS 7.0 instead of that you have to use -boundingRectWithSize:options:attributes:context: method
you can use it like below code
CGSize constraint = CGSizeMake(MAXIMUM_WIDHT, TEMP_HEIGHT);
NSRange range = NSMakeRange(0, [[self.message body] length]);
NSDictionary *attributes = [YOUR_LABEL.attributedText attributesAtIndex:0 effectiveRange:&range];
CGSize boundingBox = [myString boundingRectWithSize:constraint options:NSStringDrawingUsesFontLeading attributes:attributes context:nil].size;
int numberOfLine = ceil((boundingBox.width) / YOUR_LABEL.frame.size.width);
CGSize descSize = CGSizeMake(ceil(boundingBox.width), ceil(self.lblMessageDetail.frame.size.height*numberOfLine));
CGRect frame=YOUR_LABEL.frame;
frame.size.height=descSize.height;
YOUR_LABEL.frame=frame;
here you have to give width to maximum length for finding height or width.
try this it is working for me.

how to do truncation of text in UILabel

I have problem with truncation of text in UILabel even I have set lineBreakMode = NSLineBreakByWordWrapping perfectly.
Here is my code snippet :
lblSelectedText = [[UILabel alloc] init];
lblSelectedText.numberOfLines = 0;
lblSelectedText.lineBreakMode = NSLineBreakByWordWrapping;
lblSelectedText.font = [UIFont fontWithName:#"MyriadPro-Regular" size:(IS_IPAD_PRO?13.0:9.0)];
lblSelectedText.textAlignment = NSTextAlignmentCenter;
lblSelectedText.textColor = [UIColor lightGrayColor];
lblSelectedText.text = strKey; // Here text will be dynamic
CGFloat width = 150;
CGSize strSize = [self findHeightForText:strKey havingWidth:width andFont:lblSelectedText.font];
lblSelectedText.frame = CGRectMake(12, 10, CGRectGetWidth(aContainerController.view.frame)-20, strSize.height+15);
- (CGSize)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font
{
CGSize size = CGSizeZero;
if (text)
{
if (IS_ENGLISH) {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height + 10);
}
else {
CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{ NSFontAttributeName:font } context:nil];
size = CGSizeMake(frame.size.width, frame.size.height + 1);
}
}
return size;
}
Please note that these labels are in collection view cell. Here are some reference images.
If anyone have solution of this problem please share with me...
Thanks.
As you have mentioned in comment that some characters goes in to next line that means there is not enough width to fill every letter in single line thats why it is going to second line as you set number of line to 0(i.e. multiple lines). So there is nothing is wrong in it. It is normal behavior according to your setup made in code.
now if you want that it not goes to second line then set numberOfLines property to 1.
Another option is you can set minimunScaleFactor from 0 to 1 to resize your font to fit in available width.
You can do it something like,
label.adjustsFontSizeToFitWidth = YES;
label.minimumScaleFactor = 0.5f;
So, It will reduce font size to half of the actual to fit it in availabel width.
And once try by changing linebreakmode to NSLineBreakByTruncatingTail also instead of NSLineBreakByWordWrapping.
Check this:-
label.minimumScaleFactor = 0.5f;
label.lineBreakMode = NSLineBreakByTruncatingMiddle;
[label sizeToFit];

How do I calculate the UILabel height dynamically [duplicate]

This question already has answers here:
How to calculate UILabel height dynamically?
(14 answers)
Closed 5 years ago.
I have the following code:
label.numberOfLines = 0; // allows label to have as many lines as needed
label.text = #"some long text";
[label sizeToFit];
How do I get the height of label in points?
The easiest way to get the height is sizeThatFits. Use it like this:
Objective-C
CGFloat maxLabelWidth = 100;
CGSize neededSize = [label sizeThatFits:CGSizeMake(maxLabelWidth, CGFLOAT_MAX)];
Swift 3.0
let maxLabelWidth: CGFloat = 100
let neededSize = label.sizeThatFits(CGSize(width: maxLabelWidth, height: CGFloat.greatestFiniteMagnitude))
The height your label needs is neededSize.height.
Note that im using CGFLOAT_MAX for the size height, to make sure the label has enough place to fit in the CGSize.
The height of your label also depends on your width of the label, thats why I added maxLabelWidth, it makes a difference if the label can be 100pt wide or 200pt.
Hope this helps!
Edit:
Make sure you set label.numberOfLines = 0; otherwise neededSize returns the size where the text is in a single line.
Edit:
Added Swift version, although the naming is a bit weird, greatestFiniteMagnitude seems to be the correct equivalent for CGFLOAT_MAX.
Use following method to calculate dynamic UILabel height:
- (CGFloat)getLabelHeight:(UILabel*)label
{
CGSize constraint = CGSizeMake(label.frame.size.width, CGFLOAT_MAX);
CGSize size;
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize boundingBox = [label.text boundingRectWithSize:constraint
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:label.font}
context:context].size;
size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
return size.height;
}
Just use [label sizeThatFits:label.frame.size]; and it will return the size of label which will fit for given text. Or you can also follow the question
For those who want to estimate the size a label takes in a method which estimates header / cell height in UICollectionView or UITableView, follow this:
Set maxWidth that your label will take
Create a new UILabel and set numberOfLines to 0
Add Font attributes like custom font name and font size if using custom fonts
Set text for this label and get estimated height using sizeThatFits. Label height is neededHeight.height
Swift Version
let maxLabelWidth:CGFloat = collectionView.frame.width - 20
let label = UILabel()
label.numberOfLines = 0
let addressFont = [ NSFontAttributeName: UIFont(name: "OpenSans", size: 12.0)! ]
let addr = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
label.attributedText = NSMutableAttributedString(string: addr , attributes: addressFont )
let neededSize:CGSize = label.sizeThatFits(CGSizeMake(maxLabelWidth, CGFloat.max))
let labelHeight = neededSize.height
Thanks to #FabioBerger
I edited Salman Zaidi's answer a little to make it work better for myself. It works well if you don't have direct access to a label, like when you are trying to get label height in heightForRowAtIndexPath:
-(CGFloat)getLabelHeight:(CGSize)labelSize string: (NSString *)string font: (UIFont *)font{
CGSize size;
NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
CGSize boundingBox = [string boundingRectWithSize:labelSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:font}
context:context].size;
size = CGSizeMake(ceil(boundingBox.width), ceil(boundingBox.height));
return size.height;
}
You can Create Label dynamically :
-(CGRect)newLableSize:(NSString *)lableString
{
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
CGFloat tempwidth = YourStaticLabelWidth * ScreenWidth / 320;
NSMutableArray *array=[[NSMutableArray alloc]initWithObjects: lableString,nil];
CGRect newLabelsize = [[array objectAtIndex:0] boundingRectWithSize:CGSizeMake(tempwidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:selectFont,NSParagraphStyleAttributeName:paragraphStyle} context:nil];
NSLog(#"New Label Size Width : %f",newLabelsize.size.width);
NSLog(#"New Label Size Height : %f",newLabelsize.size.height);
return newLabelsize;
}
I'm adjust height, with 2 lines in my label
lblUserQuestion.preferredMaxLayoutWidth = 100.0f;
100.0f, it's a size i wanted, and another line,
[lblUserQuestion sizeToFit];
My method complete is,
UILabel *lblUserQuestion = [[UILabel alloc] initWithFrame:CGRectMake(61, 25, self.frame.size.width-61-20, 37.0f)];
lblUserQuestion.numberOfLines= 0;
lblUserQuestion.font =[UIFont fontWithName:#"HelveticaNeue-Thin" size:14.];
lblUserQuestion.adjustsFontSizeToFitWidth = YES;
lblUserQuestion.minimumScaleFactor = 0.5;
lblUserQuestion.preferredMaxLayoutWidth= 100.0f;
lblUserQuestion.text = _photoToVote.label;
- (CGFloat)getTextHeightByWidth:(NSString*)text textFont:(UIFont*)textFont textWidth:(float)textWidth {
if (!text) {
return 0;
}
CGSize boundingSize = CGSizeMake(textWidth, CGFLOAT_MAX);
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text attributes:#{ NSFontAttributeName: textFont }];
CGRect rect = [attributedText boundingRectWithSize:boundingSize options:NSStringDrawingUsesLineFragmentOrigin context:nil];
CGSize requiredSize = rect.size;
return requiredSize.height;
}
- (CGFloat)getTextWidthByHeight:(NSString*)text textFont:(UIFont*)textFont textHeight:(float)textHeight {
if (!text) {
return 0.0f;
}
CGSize boundingSize = CGSizeMake(CGFLOAT_MAX, textHeight);
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:text
attributes:#{ NSFontAttributeName: textFont }];
CGRect rect = [attributedText boundingRectWithSize:boundingSize
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize requiredSize = rect.size;
return requiredSize.width;
}
Use this function
+ (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;
}
- (CGFloat)getLabelsize:(UILabel *)label
{
CGSize maxSize = CGSizeMake(label.frame.size.width, 9999);
CGSize requiredSize = [label sizeThatFits:maxSize];
return requiredSize.height;
}

UILabel Dynamic Width calculation Multiple Lines

I have UILabel where i have 2 lines of text. I used the below code to calculate the dynamic width and height
CGSize expectedLabelSize = [[aLabel text] sizeWithFont:aLabel.font
constrainedToSize:aLabel.frame.size
lineBreakMode:aLabel.lineBreakMode];
CGRect rect = [aLabel frame];
rect.size.width = expectedLabelSize.width;
[aLabel setFrame:rect];
Now if there is multiple lines in the UILabel how can i detect the width. See the image for more clearence.
set property for Label
label.numberOfLines = 0;
CGFloat labelHeight= [self heightOfLabelWithIngredientLine:pixers.name];
[label setFrame:CGRectMake(10,10,100,labelHeight)];
- (CGFloat)heightOfLabelWithIngredientLine:(NSString *)stringLabel
{
CGRect frame;
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys: [UIFont fontWithName:#"Helvetica" size:14.0f], NSFontAttributeName, nil];
frame = [stringLabel boundingRectWithSize:CGSizeMake(20.0f, 999.0f) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:attributesDictionary context:nil];
return frame.size.height;
}
Customize your label properties in
- (CGFloat)heightOfLabelWithIngredientLine:(NSString *)stringLabel
method.

iOS 7 uitextview NSLineBreakByWordWrapping not working

In iOS 7 I use new method to calculate the textview height,but it seems that it's not word wrapping, besides,the height is not the height of the text.
self.textview.textContainer.lineBreakMode = NSLineBreakByWordWrapping;
self.textview.showsHorizontalScrollIndicator= NO;
self.textview.showsVerticalScrollIndicator = NO;
// [self.textview sizeThatFits:CGSizeMake(296, 474)];
// [self.textview.text sizeWithFont:[UIFont systemFontOfSize:14] forWidth:296.0 lineBreakMode:NSLineBreakByWordWrapping];
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
[paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];
NSDictionary *attributes = #{ NSFontAttributeName: self.textview.font, NSParagraphStyleAttributeName : paragraphStyle };
//
CGSize size= [self.textview.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(self.textview.frame), MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil].size;
CGRect frame = self.textview.frame;
frame.size = size;
self.textview.frame= frame;
anyone help?
solved the problem it's because the text has wrong white charter ,that is it replace white character with other character.
Try this:
CGSize maximumLabelSize = CGSizeMake(295,99999);
CGSize expectedLabelSize = [self.textview. sizeWithFont:self.textview..font constrainedToSize:maximumLabelSize lineBreakMode:self.textview.lineBreakMode];
//adjust the label the the new height.
CGRect newFrame = self.textview.frame;
newFrame.size.height = expectedLabelSize.height;
self.textview.frame = newFrame;
Check image having your given text : http://screencast.com/t/Yqr6oSOvhN1
I had a similar problem because I had a wrong character space.
For replace I used:
message = [message stringByReplacingOccurrencesOfString:#"\u00A0" withString:#“ "];

Resources