Objective-C: Text on my UILabel is not wrapping properly - ios

I'm having a little trouble with a uilabel that should display 1 of 5 random strings. Sometimes the entire string displays with no problem, but more often than not, some of the text is cut off. Here's what I currently have:
// These are the 5 NSStrings which are placed in an array.
NSString *badOne = #"Bad? Your bill is nothing. I would consider that good service. SMDH.";
NSString *badTwo = #"You left out the amount dude.";
NSString *badThree = #"I can't tell you what the tip should be, if you don't tell me how much you dropped.";
NSString *badFour = #"Forgetting something?";
NSString *badFive = #"The tip should be over 9000... /n kidding.";
NSArray *badComments = [[NSArray alloc] initWithObjects:badOne, badTwo, badThree, badFour, badFive, nil];
// A random string is selected and assigned to badJoke.
int rand = arc4random()%5;
NSString *badJoke = [badComments objectAtIndex:rand];
// Here's the problematic code:
[_mainLabel setText:(badJoke)];
[_mainLabel setFrame:CGRectMake(50, 295, 200, 80)];
_mainLabel.adjustsFontSizeToFitWidth = NO;
_mainLabel.numberOfLines = 0;
[_amountTextField resignFirstResponder];
// This is a separate label, completely unrelated.
[_tipAmount setText:#""];
So for example, one of the times it might show "Bad? Your bill is no".
I've also tried without the setFrame line and no luck.
Any help would be appreciated. Thanks.

Ideal solution is to calculate the exact frame needed to display the text inside the lable...
NSString *badJoke = [badComments objectAtIndex:rand];
CGSize maximumSize = CGSizeMake(200, CGFLOAT_MAX);//you can give any max width which you feel that suits you...
UIFont *font = [UIFont systemFontOfSize:16];/Give your font size
CGSize size = [badJoke sizeWithFont:font constrainedToSize:maximumSize lineBreakMode:NSLineBreakByWordWrapping];
//size.height will get you the total height of the lable to be created.
_mainLable=[[UILable alloc]initWithFrame:CGRectMake(50, 295, size.width, size.height)];
//if you haven't initialized.Or else you can use the same as you were using..[_mainLabel setFrame:CGRectMake(50, 295, size.width, size.height)];
_mainLabel.text= badJoke;
_mainLabel.lineBreakMode=NSLineBreakByWordWrapping;
_mainLabel.numberOfLines = 0;
I am not sure with the syntax,because i wrote the code on my notepad.Hope it works for you.Happy coding :)

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));
}

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.

How to find all characters in the first line of the uilabel

I want to calculate number of lines and find all characters in the first line of the UILabel dynamically from given text. I'm using wordwrapping for uilabel. Is it possible. Please help and guide me.
try like this
UILabel *thisyourlabel = [[UILabel alloc] initWithFrame:CGRectZero];
thisyourlabel.numberOfLines = 0;
thisyourlabel.lineBreakMode = UILineBreakModeWordWrap;
thisyourlabel.text = #"I want to calculate number of lines and find all characters in the first line of the UILabel dynamically from given text. I'm using wordwrapping for uilabel. Is it possible. Please help and guide me";
CGRect frame = thisyourlabel.frame;
frame.size.width = 200.0f;
frame.size = [thisyourlabel sizeThatFits:frame.size];
thisyourlabel.frame = frame;
CGFloat lineHeight = thisyourlabel.font.leading;
NSUInteger linesInLabel = floor(frame.size.height/lineHeight);
NSLog(#"Number of lines in label: %i", linesInLabel);
[self.view addSubview: thisyourlabel];

Initializing words of a sentence stored in a string into UILabels

I am trying to initialise the words of a sentence into UIlabels in the order of the word of the sentence every time I click on a UIbutton.
I also want to recognise when the sentence in the different labels is approaching the end of the screen, which then takes the next word and puts it in the line below the words of the sentence like pressing Enter in Microsoft Word.
I have tried this code but it loads all the words on the same spot.
- (void)change:(id)sender
{
NSString *sentence = #"i am a boy with passion";
NSArray *array = [sentence componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#" "]];
CGFloat xVal = 11.0;
for (NSString *words in array) {
UILabel *labelText = [[UILabel alloc]initWithFrame:CGRectMake(xVal, 50, 300, 80)];
labelText.layer.borderColor = [UIColor blueColor].CGColor;
labelText.layer.borderWidth = 6.0;
labelText.backgroundColor = [UIColor clearColor];
labelText.textColor = [UIColor blackColor];
labelText.font = [UIFont boldSystemFontOfSize:20.0f];
labelText.text = words;
xVal=+200;
[self.view addSubview:labelText];
[labelText setUserInteractionEnabled:YES];
[labelText sizeToFit];
xVal=+200; means xVal=200. So except first label all others got same origin. Thats why they got over lapped.
For finding whether the label moved out of bounds
Initialise yVal outside for loop,
Inside the loop add
CGFloat width = [words sizeWithFont:[UIFont systemFontOfSize:[UIFont systemFontSize]]].width;
if (self.view.frame.size.width<xVal+width) {
yVal+=50;
xVal = 11;
}
UILabel *labelText = [[UILabel alloc]initWithFrame:CGRectMake(xVal, yVal, 300, 80)];
Make sure to use, a)the font you would be using for label in finding the width, b) adjust increment in yVal according to yor need.
Dont forget to change xVal=+200; to xVal+=200;
Your problem is this line:
xVal=+200;
This is the same as saying xVal = 200; the plus sign means positive 200 rather than 200 more. Try this instead:
xVal += 200;

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