UILabel with "+" text not centered vertically - ios

self.iconLabel.frame = self.contentView.frame;
self.iconLabel.font = [UIFont systemFontOfSize:100.0];
self.iconLabel.text = #"+";
self.iconLabel.textColor = [UIColor blackColor];
self.iconLabel.textAlignment = NSTextAlignmentCenter;
So the UILabel's frame is the same size as its container view, self.contentView
I need the "+" to be centered vertically also, I want it in the center.
How can I achieve this?
My only notion is to shift the iconLabel.frame up.
EDIT: Changed from self.iconImageView to self.contentView which is a UIView. The UILabel is layered above the self.iconImageView which is a UIImageView.
EDIT 2: Tried implementing kshitij godara's code, the result is:
I altered the code slightly:
CGSize constraint = CGSizeMake(self.contentView.frame.size.width, self.contentView.frame.size.height);
NSString *str = #"+";
UIFont *myFont = [UIFont systemFontOfSize:100.0];
CGSize stringSize = [str sizeWithFont:myFont constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
self.iconLabel.frame = CGRectMake(0, 0, stringSize.width, stringSize.height);
self.iconLabel.font = myFont;
self.iconLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.iconLabel.numberOfLines = 0;
[self.iconLabel sizeToFit];
self.iconLabel.text = str;
EDIT 3:
the frame is quite large:

This is probably a problem of the font itself. Each font has defined it shapes, behavior, typesetting etc. The font seems to be positioning character "+" of the visual vertical center. You can test it on any other string containing letter "+", "dog+Cat" for example. The "+" letter will probably be drawn near bottom as it is on your image.
From my point of view, you have 2 options:
Use icon image instead for the "+" sign. This will be simplest and the best working solution
Use custom font edited to visually look exactly like you need (letter "+" totally centered in its typeset). This one would probably be very painfull and time-consuming option
Edit: Regarding 2nd option: I have already done such an procedure to fix some misaligned fonts following this tutorial. However it still just fixes the whole font, not on a single character basis

You can do this -- Try to apply this
CGSize constraint = CGSizeMake(iconImageFrame.size.width,1000.0f);
//Now Calculate size of string
NSString *str = #"+";
//Always give the same font to calculate size which you giving for label
UIFont *myFont = [UIFont systemFontOfSize:100.0];
CGSize stringSize = [str sizeWithFont:myFont
constrainedToSize:constraint
lineBreakMode:UILineBreakModeWordWrap];
//now set same font for uilabel and also make it to fit to size
//like this
UILabel *myLabel = [[UILabel alloc]initWithFrame:CGRectMake(myIconLabelFrame.x,myIconLabelFrame.y,stringSize.width,stringSize.height)];
myLabel.font = myFont;
myLabel.lineBreakMode = UILineBreakModeWordWrap;
myLabel.numberOfLines = 0;
[myLabelsizeToFit];
myLabel.text = str;
As now label will be completely fit in size , therefore it will always be in center .This code also can be used for to increase height of label dynamically .
I hope it solve your problem .Thanks!

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

iOS - Change UILabel font size proportionally

I have several UILables in my view like this:
Those in red colour should never change their font size. Two others in white colour (50 and 50) should decrease their font size proportionally to fit the content.
What I want to achieve is when any of white labels becomes two big the other should start decreasing in size as well:
but instead I get this:
How can I make my UILabels' font size to resize proportionally?
The easiest possible way is as below:
Identify the max possible widths of label 1 and label2.
Sum up widths of both label.
Append both the strings which you want to set in both labels.
Get the font size that fits given (combined) text in combined width.
Now calculate the width of first text for above identified font size and assign it to first label.
Adjust rest of the labels frame according to its frame.
Similarly identify the width of second label.
Assign above derived font size to both labels.
One easy way to do this is by adjusting the fontSize manually using UILabel's sizeToFit method to calculate its bounds.
int fontSize = MAX_FONTSIZE;
BOOL fontSizeNeedsToBeAdjusted = NO;
CGRect originalLabelFrame1 = label1.frame;
CGRect originalLabelFrame2 = label2.frame;
while(fontSizeNeedsToBeAdjusted && fontSize>MIN_FONTSIZE){
label1.frame = originalLabelFrame1;
label1.font = [UIFont systemFontOfSize:fontSize];
[label1 sizeToFit];
label2.frame = originalLabelFrame2;
label2.font = [UIFont systemFontOfSize:fontSize];
[label2 sizeToFit];
if(CGRectGetWidth(label1.frame)>CGRectGetWidth(originalLaeblFrame1) || CGRectGetHeight(label1.frame)>CGRectGetHeight(originalLaeblFrame1))
|| CGRectGetWidth(label2.frame)>CGRectGetWidth(originalLaeblFrame2) || CGRectGetHeight(label2.frame)>CGRectGetHeight(originalLaeblFrame2)){
fontSizeNeedsToBeAdjusted = YES;
fontSize--;
}else
fontSizeNeedsToBeAdjusted = NO;
}
A quicker way would be calculating the size with NSString's boundingRectWithSize: options:attributes:context: method:
NSDictionary *attributes = #{NSFontAttributeName: [UIFont systemFontofSize:fontSize]};
// NSString class method: boundingRectWithSize:options:attributes:context is
// available only on ios7.0 sdk.
CGRect bounds = [label1.text boundingRectWithSize:CGSizeMake(CGRectGetWidth(label1.frame), MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributes
context:nil];
I expected the answer to this is in NSMutableAttributedString so i did a small experiment with this
NSString *quantity = #"123456";
NSString *metrics =#"m2";
NSString *quantity2 = #"50";
NSString *metrics2 =#"pk";
NSString *separator = #" / ";
NSMutableAttributedString *fullString = [[NSMutableAttributedString alloc] initWithString:
[NSString stringWithFormat:#"%#%#%#%#%#",quantity,metrics,separator,quantity2,metrics2]];
[fullString addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:25.0]
range:NSMakeRange(quantity.length+metrics.length, separator.length)];
[fullString addAttribute:NSFontAttributeName
value:[UIFont systemFontOfSize:12.0]
range:NSMakeRange(fullString.length-metrics.length, metrics.length)];
_lblTitle.attributedText = fullString;
So try changing the values and adding attributes you will get what you want

UILabel shows fewer lines then expected with multiple lines mode

I'd like my UILabel to show my data in multiple lines, and the data is fetch from txt file.
I've searched online for this question, and all the answers show that I just need to set lineBreakMode to NSLineBreakByWordWrapping and numberOfLines = 0. However, the problem is that, even though I added these settings, the labels shows fewer lines than expected (my data has 4 lines, however the label only shows 2 lines). Here's my code:
-(void)updateFileContentLabel:(NSString*)content{
self.fileContentLabel.text = content;
self.fileContentLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.fileContentLabel.font = [UIFont systemFontOfSize:17.0f];
self.fileContentLabel.numberOfLines = 0;
[self.fileContentLabel sizeToFit];
NSLog(#"file Label: %#",self.fileContentLabel.text);
}
As you see, I have a NSLog to show the content of label's text. And the text of label in NSLog is correct (4 lines). However on the phone or simulator, it only shows 2 lines instead of 4. Does anyone know where is the problem? Thanks!
Probably your UILabel is just not big enough. Solutions:
1.Increase a label size.
2.Add following code to allow UILabel to decrease the font size if needed.
self.fileContentLabel.minimumScaleFactor = 0.5;
I was only able to replicate your problem when I was using auto layout and didn't have constraints set up for fileContentLabel, so check that out.
Use the following method to calculate the height of text and set the frame of label accordingly.
- (CGSize)boundingSizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode
{
CGSize stringSize;
if ([self respondsToSelector:#selector(boundingRectWithSize:options:attributes:context:)]) {
NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
paragraphStyle.lineBreakMode = lineBreakMode;
NSDictionary * stringAttributes = #{ NSFontAttributeName: font, paragraphStyle: NSParagraphStyleAttributeName};
stringSize = [self boundingRectWithSize:size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:stringAttributes context:nil].size;
stringSize = CGSizeMake(ceil(stringSize.width), ceil(stringSize.height) + 2);
} else {
stringSize = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode];
}
return stringSize;
}

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. :)

Why is UIFont sizeWithFont including blank space in its calculation?

I am setting a UILabels frame based on what is returned by UIFont sizeWithFont but for whatever reason when i use a custom font, the values that are returned include some padding as seen below.
When i use boldSystemFontOfSize the text is vertically aligned in the middle (which is what i want), but when i use fontWithName i end up with padding under the text. Any reason why sizeWithFont is adding in the padding?
Heres my code...
CGRect frameLabel = label.frame;
CGSize sizeLabel = [label.text sizeWithFont:label.font];
frameLabel.size.width = sizeLabel.width;
frameLabel.size.height = sizeLabel.height;
[label setBackgroundColor:[UIColor redColor]];
** Edit **
I can calculate the top and bottom padding using this code and adjust the labels frame.origin.y to vertically center my label where it needs to be
float topPadding = [label.font ascender] - [label.font capHeight];
float bottomPadding = [label.font lineHeight] - [label.font ascender];
Font is the only possible cause of this padding, but if you only need one-line labels, don't waste your time editing the font, just reduce the label's height by those few pixels after setting a proper frame by doing something like this:
label.frame = CGRectInset(label.frame, 0, bottomPadding);
Also, instead of:
CGRect frameLabel = label.frame;
CGSize sizeLabel = [label.text sizeWithFont:label.font];
frameLabel.size.width = sizeLabel.width;
frameLabel.size.height = sizeLabel.height;
You can just call:
[label sizeToFit];

Resources