Calculate the minimum rectangle around text in UIlabel - ios

I programmatically create some text.
The text gets attributes and then returns to the view controller where is displayed.
Originally i create a rectangle UIlabel with max height 40.
Therefore if the the text is too big the font size decreases to fit into the rectangle by
applying to the text adjustsFontSizeToFitWidth.
If the text is small there is a lot of empty space in the rectangle (on top and below).
Is it possible at that point to get the minimum rectangle eclosing my text.
Thank you
.
NSAttributedString * Text=[circleModel.Selected_set objectForKey:#"sentence_text"];
CGRect recty;
recty= CGRectMake(mainScreen.size.width*0.55, 100, mainScreen.size.width*0.43,40);
UILabel *Latex_text = [[UILabel alloc] initWithFrame:recty];
Latex_text.AttributedText = Text;
Latex_text.numberOfLines = 0;
Latex_text.adjustsFontSizeToFitWidth = YES;
Latex_text.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:Latex_text];
//Latex_text.backgroundColor = [UIColor whiteColor];

What about using textRectForBounds? It should give you at least an estimate if the adjustsFontSizeToFitWidth doesn't play well with it.
UILabel *Latex_text = [[UILabel alloc] init];
Latex_text.AttributedText = Text;
Latex_text.numberOfLines = 0;
Latex_text.adjustsFontSizeToFitWidth = YES;
Latex_text.textAlignment = NSTextAlignmentCenter;
recty.size = [Latex_text textRectForBounds:recty limitedToNumberOfLines:0].size;
[Latex_text setFrame:recty];

Related

Putting text in Circle as big as possible

It´s a pretty basic problem but I couldn´t find a proper solution for it. I have several circles which have text in it like you can see in the picture. The text gets loaded dynamically and has a size from one word up to five words or more. The goal is to put the text as big as possible into the circle. New lines can appear but every individual word should stay together. The example image is kind of ok but I would prefer the text to be bigger because there is still some free space between the text and the circle. The circle is 80x80. All solution I tried cropped the text strangly or the text is too small.
How I create the label:
UILabel *buttonlabel = [[UILabel alloc] initWithFrame:CGRectMake(12,7,57,64)];
[buttonlabel setText: #"Recipes"];
buttonlabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:18.0f];
buttonlabel.textColor = [UIColor whiteColor];
buttonlabel.textAlignment = NSTextAlignmentCenter;
buttonlabel.lineBreakMode = NSLineBreakByWordWrapping;
buttonlabel.numberOfLines = 3;
[button addSubview:buttonlabel];
[buttonlabel release];
EDIT:
So I tried the solution of Rufel. I think the shrinking kind of works but my words get ripped apart. Even though I have buttonlabel.lineBreakMode = NSLineBreakByWordWrapping;
It looks like this:
This is my code. I also implemented the other methods mentioned in an answer.
//Create the button labels
UILabel *buttonlabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 60, 60)];
[buttonlabel setText: #"text";
buttonlabel.textColor = [UIColor whiteColor];
buttonlabel.textAlignment = NSTextAlignmentCenter;
buttonlabel.lineBreakMode = NSLineBreakByWordWrapping;
buttonlabel.numberOfLines = 0;
CGFloat fontSize = 20; // The max font size you want to use
CGFloat labelHeightWithFont = 0;
UIFont *labelFont = nil;
do {
// Trying the current font size if it fits
labelFont = [UIFont systemFontOfSize:fontSize--];
CGRect boundingRect = [self boundingRectForString:subcatbuttontitlesarray[buttonTag-1] font:labelFont];
labelHeightWithFont = boundingRect.size.height;
// Loop until the text at the current size fits the maximum width/height.
} while (labelHeightWithFont > [self buttonLabelMaxWidth]);
buttonlabel.text = subcatbuttontitlesarray[buttonTag-1];
buttonlabel.font = labelFont;
- (CGRect)boundingRectForString:(NSString *)string font:(UIFont *)font
{
return [string boundingRectWithSize:CGSizeMake([self buttonLabelMaxWidth], MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
attributes:#{NSFontAttributeName: font}
context:nil];
}
- (CGFloat)buttonLabelMaxWidth
{
CGFloat hypotenuse = CGRectGetWidth(CGRectMake(0, 0, 60, 60));
CGFloat rightTriangleCathetus = sqrtf((hypotenuse*hypotenuse)/2);
return rightTriangleCathetus;
}
I found this thread here:
iOS7 - Adjusting font size of multiline label to fit its frame
which has the same problem.
Edit 2:
After searching a complete day for the solution and trying all kinds of combinations of the label attributes I somehow figured out that the "numberoflines" is my culprit. So I came up with this dumb solution of counting the words in the string and adjust the number of lines based on the numbers of the string:
NSString *samplestring = #"Three words string";
//Count the words in this string
int times = [[samplestring componentsSeparatedByString:#" "] count]-1;
UILabel *testlabel = [[UILabel alloc]initWithFrame:CGRectMake(30, 30, 60, 60)];
[testlabel setText:samplestring];
[testlabel setFont:[UIFont fontWithName:#"HelveticaNeue-UltraLight" size:40.0f]];
[testlabel setBackgroundColor:[UIColor redColor]];
[testlabel setAdjustsFontSizeToFitWidth:YES];
[testlabel setTextAlignment:NSTextAlignmentCenter];
//My workaround
if(times ==0){
[testlabel setNumberOfLines:1];
}else{
if(times==1){
[testlabel setNumberOfLines:2];
}
else{
[testlabel setNumberOfLines:3];
}}
[self.view addSubview:testlabel];
What you want to do, I think, is to ask the NSString for its boundingRectWithSize:options:attributes:context:. By setting the width of the bounding rect, you can find out what the height would be. You can use the parametric formula for the circle to determine whether that bounding rect fits entirely within the center of the circle. Unfortunately you will have to perform a kind of trial-and-error sequence of approximations, where the text gets larger and larger until the top and bottom stick out of the circle, and then narrow the proposed width and see whether this causes the height to grow too much because the text now wraps an extra time.
Say you have a custom view in which you draw a circle that fits its frame (80x80 in your example).
You will first want to find the maximum width your label can take without letters crossing the circle:
- (CGFloat)buttonLabelMaxWidth
{
CGFloat hypotenuse = CGRectGetWidth(self.bounds);
CGFloat rightTriangleCathetus = sqrtf((hypotenuse*hypotenuse)/2);
return floorf(rightTriangleCathetus);
}
Next, when you pass the title to display, you will want to iterate by decreasing an initially oversized font until the resulting string boundary fits the width previously calculated (which is also the maximum height since it's a circle). UPDATE: You will also want to check every words in the title to be sure they are not being truncated (that they fit the maximum width).
- (void)setButtonTitle:(NSString *)title
{
CGFloat fontSize = 20; // The max font size you want to use
CGFloat minimumFontSize = 5; // The min font size you want to use
CGFloat labelHeightWithFont = 0;
CGFloat longestWordWidth = 0;
UIFont *labelFont = nil;
CGFloat buttonLabelMaxWidth = [self buttonLabelMaxWidth];
do {
if (fontSize < minimumFontSize) {
// Handle exception where the title just won't fit
break;
}
// Trying the current font size if it fits
labelFont = [UIFont systemFontOfSize:fontSize--];
CGSize boundingSize = [self boundingSizeForString:title font:labelFont];
labelHeightWithFont = boundingSize.height;
// Be sure that words are not truncated (that they fits in the maximum width)
longestWordWidth = 0;
for (NSString *word in [title componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) {
CGSize wordSize = [word sizeWithAttributes:#{NSFontAttributeName: labelFont}];
longestWordWidth = MAX(longestWordWidth, wordSize.width);
}
// Loop until the text at the current size fits the maximum width/height.
} while (labelHeightWithFont > buttonLabelMaxWidth || longestWordWidth > buttonLabelMaxWidth);
self.buttonLabel.text = title;
self.buttonLabel.font = labelFont;
}
- (CGSize)boundingSizeForString:(NSString *)string font:(UIFont *)font
{
CGRect boundingRect = [string boundingRectWithSize:CGSizeMake([self buttonLabelMaxWidth], MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading
attributes:#{NSFontAttributeName: font}
context:nil];
return CGSizeMake(ceilf(boundingRect.size.width), ceilf(boundingRect.size.height));
}

Centered Single Character in UILabel off by 1 pixel

I am setting up the following UILabel:
UIImageView *textImageBackground = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"top100bar"]];
textImageBackground.frame = CGRectMake( 104.0f, 6.0f, 215.0f, 104.0f);
[self.contentView addSubview:textImageBackground];
_lblRank = [[UILabel alloc] init];
self.lblRank.textColor = [UIColor whiteColor];
self.lblRank.textAlignment = NSTextAlignmentCenter;
self.lblRank.font = [UIFont fontWithName:#"HelveticaNeue-Medium" size:10];
self.lblRank.frame = CGRectMake(153.0f, 45.0f, 41.0f, 41.0f);
self.lblRank.backgroundColor = [UIColor colorWithRed:.09 green:.62 blue:.11 alpha:1.0];
[textImageBackground addSubview:_lblRank];
If the text of _lblRank is set to a string 2 or more characters long, it centers the text perfectly, with an equal amount of pixels to the left and right of the text. However, if the string only has a single character, the text favors the left by 1 or 2 pixels. I measured this by grabbing a screenshot of the simulator and zooming and measuring in Preview.
I have attached screenshots of single and multi character versions.
Thanks so much!
Stephen
First size to fit the label:
[self.lblRank sizeToFit]
Then center it horizontally:
CGRect frame = self.lblRank.frame
frame.origin.x = self.lblRank.superview.frame.size.width/2.0 - frame.size.width/2.0;
self.lblRank.frame = frame
Make sure the label has a superview before you use the code above.

Adding UILabels to UIView dynamically

I have a web service that brings some text data back. The idea is to extract the text and create UILabels for the text to show on screen. I however, do not know two things:
How many labels are needed
The length of the text
Due to having no prior knowledge of these things I need a way to create some labels that have the right length for the text it contains.
I've managed to store the data into some objects that are in an array and then iterate through them creating the labels.. something like this:
for (BBItemAttributes *attribute in self.item.productAttributes){
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 50, 10)];
label.text = attribute.displayTemplate;
[self.scrollView addSubview:label];
}
Obviously the problem here is due to creating the UILabels in code and having each one a hard coded CGRect size they are all onto of each other and sometimes don't fit in their respective boxes due to text being too long.
I need a way to line the labels up all on the same X axis point and on different Y axis points, so that they sit next to each other a certain space apart.
Is there a better way to do this?
You need to do something like this;
CGFloat yOrigin = 100;
CGFloat fixedSpace = 10;
for (BBItemAttributes *attribute in self.item.productAttributes)
{
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(100, yOrigin, 50, 10)];
label.text = attribute.displayTemplate;
label.numberOfLines = 0;
[label sizeToFit]; // Resizes label to fit the text.
[self.scrollView addSubview:label];
yOrigin += label.frame.size.height + fixedSpace;
}
Try this. it will help you.
float yAxis = 0;
for (int i = 0; i< 50; i++)//for (BBItemAttributes *attribute in self.item.productAttributes){
{
CGSize size;
UIFont *font = [UIFont systemFontOfSize:15.0]; // Set Your Font
//Your String = attribute.displayTemplate
if (ios7)//Condition to check if ios7
{
//iOS 7
CGRect frame = [#"Your String" boundingRectWithSize:CGSizeMake(50, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:font}
context:nil];
size = CGSizeMake(frame.size.width, frame.size.height+1);
}
else
{
//iOS 6.0
size = [#"Your String" sizeWithFont:font constrainedToSize:CGSizeMake(50, CGFLOAT_MAX) lineBreakMode:NSLineBreakByWordWrapping];
}
UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(100, yAxis, 50, size.height)];
label.text = #"Your String";//attribute.displayTemplate
label.numberOfLines = 0;
label.tag = i; // Set tag if you want to access in future. :)
[self.scrollView addSubview:label];
// Increase yAxis
yAxis = yAxis + size.height + 10;//10 is extra space if you want between two label
}
// Do Not forget to set Contentsize of your ScrollView.
self.scrollView.contentSize = CGSizeMake(320, yAxis + 20);
If your showing a data structure that is a like a list of labels, I would suggest that you use UITableViewController for showing the list.It has the built in facility and properties that make it easy to display a list of objects.
Now the answer to your first Question.You can get the number of labels by determining the number of objects that are in your array. Something like this :
NSInteger *noOfLabels = yourArray.count;
As far as the length of the text is concerned, I suggest not keeping it very lengthy because Labels are not good for lengthy texts. You can however, specify the number of a lines for a particular label in case if it has lengthy text.This will make the text appear in two lines. Though you will have to adjust width and height accordingly.
You can get the text length by doing something similar to this :
NSString *text;
NSInteger *i = (NSInteger*)[text length];
Hope this helps.

Having difficulty wrapping text

I use the following code to add text in IOS
//Set up label frame
UILabel *tempLabel = [[UILabel alloc]initWithFrame:CGRectMake(100, 10, 210, 80)];
self.answer_text_label = tempLabel;
[tempLabel release];
[self.preview_answer_container addSubview:self.answer_text_label];
//Populate label with text
self.answer_text_label.text = self.answer.text;
self.answer_text_label.numberOfLines = 4;
self.answer_text_label.lineBreakMode = UILineBreakModeWordWrap;
[self.answer_text_label sizeToFit];
However, the result I get is as such, the text seems to overflow to the right instead of staying within the frame as stipulated in my label setup 'CGRectMake(100, 10, 210, 80)'
The wrapping works if I change to self.answer_text_label.numberOfLines = 0. But this will not work for me since I need to constrain the text within my stipulated label frame.
Any way I can wrap the text and keep to only 4 lines?
EDIT:
Try the suggested code
self.answer_text_label.text = self.answer.text;
[self.answer_text_label sizeToFit];
CGRect labelRect = self.answer_text_label.frame;
labelRect.origin.y = CGRectGetMaxY(labelRect);
labelRect.size = self.answer_text_label.frame.size;
self.answer_text_label.frame = labelRect;
result as follows. Did not seem to solve my problem
Try setting frame explicitly -
[self.answer_text_label sizeToFit];
CGRect labelRect = self.answer_text_label.frame;
labelRect.origin.y = CGRectGetMaxY(labelRect);
labelRect.size = self.answer_text_label.frame.size;
self.answer_text_label.frame = labelRect;
EDIT - Don't need to use this, just use following -
remove these of code just use below, no other property of frame, remove sizeToFit as well -
self.answer_text_label.numberOfLines = 4;
self.answer_text_label.lineBreakMode = UILineBreakModeWordWrap;
For vertical alignment - (With above line of code, use this as well, and do don't use size to fit)
CGSize textSize = [self.answer_text_label.text sizeWithFont:self.answer_text_label.font
constrainedToSize:CGSizeMake(self.answer_text_label.frame.size.width, MAXFLOAT)
lineBreakMode:self.answer_text_label.lineBreakMode];
self.answer_text_label.frame = CGRectMake(20.0f, 20.0f, textSize.width, textSize.height);
In iOS 6 and later, use NSLineBreakByWordWrapping, not UILineBreakModeWordWrap.
self.answer_text_label.lineBreakMode = NSLineBreakByWordWrapping;

iOS, how to draw the dynamic length of text?

The picture is: http://www.flickr.com/photos/71607441#N07/6641626163/
The background is a UIImageView, and the blue part I want to show as "title" of the image.
I used UILabel, but the length of the text is dynamic. It can be one line or two line, at most two line. If the text is longer than two lines, it will be truncated.
The blue part looks like "highlight in Microsoft Word", but it is not "highlight in iOS UILabel.text"
Is there anyone can help me?
Try this code :----
CGSize maximumSize = CGSizeMake(320, 30);
UILabel *newsLabel = [[UILabel alloc] init];
newsLabel.textColor = [UIColor whiteColor];
newsLabel.font = [UIFont boldSystemFontOfSize:11];
newsLabel.backgroundColor = [UIColor clearColor];
newsLabel.lineBreakMode = UILineBreakModeWordWrap;
newsLabel.numberOfLines = 0;
lineBreakMode:newsLabel.lineBreakMode];
CGSize dateStringSize = [#"Text Input" sizeWithFont:newsLabel.font
constrainedToSize:maximumSize
lineBreakMode:newsLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(5, 5, 320, dateStringSize.height); //breath can be any desired float value
newsLabel.text = #"Text Input";
newsLabel.textAlignment = UITextAlignmentCenter;
newsLabel.frame = dateFrame;
You can find the size in pixels required for your title using:
CGSize size = [UILabel.text sizeWithFont:yourFont];
there's also:
CGSize size = [UILabel.text sizeWithFont:yourFont lineBreakMode: yourLineBreakMode];
You could then use these dimensions (size.width, size.height) to set the frame of your UILabel.
Hope this helps. :)

Resources