UILabel text alignment issues in iphone? - ios

I am getting JSON response from server and set that contents to UILabel and sometimes the text will be one line and sometimes the text will be 10 lines.So i display this UILabel inside the UIScrollView. But i got the empty space in UILabel
This is my screenshots..
Currently i am using storyboard and auto layout
So i want to avoid these empty space in UILabel. Please give me suggestions for this alignment issues.??
Code for changing UILabel height but this is not working for me
CGRect textRect = [strDetailsFinal boundingRectWithSize:CGSizeMake(296, FLT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName: labDetails.font}
context:nil];
CGSize size = textRect.size;
CGRect newFrame = labDetails.frame;
newFrame.size.height = size.height;
labDetails.frame = CGRectMake(160, 200, 300, newFrame.size.height);

May this help you
NSDictionary *attributesDic= [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:#"FontName" size:15], NSFontAttributeName,nil];
CGRect frame = [label.text boundingRectWithSize:CGSizeMake(263, 2000.0)
options:NSStringDrawingUsesLineFragmentOrigin attributes:attributesDic context:nil];
CGSize size = frame.size;
and its possible answer Dynamically resize label in iOS 7 or you can try this https://gist.github.com/danielphillips/1005520

Use [labDetails sizeToFit]. If you have size constraints then use [sizeThatFits:CGSizeMake(WidthConstraint, HeightConstraint)] then use the result of that to set your label frame.

why don't you use UIButton instead of UILabel. UIButton has property to align the text vertically, while UILabel doesn't.
Use UIButton with userInteractionEnabled = NO. Check my this reply here: Vertically align UILabel

Remember one thumb rule - You should not set frame when using autolayout - You are going against Autolayout basic concept - Instead try to autolayout constraints programatically in your case
-(void)awakeFromNib{
[super awakeFromNib];
for(NSLayoutConstraint *cellConstraint in self.constraints){
[self removeConstraint:cellConstraint];
id firstItem = cellConstraint.firstItem == self ? self.contentView : cellConstraint.firstItem;
id seccondItem = cellConstraint.secondItem == self ? self.contentView : cellConstraint.secondItem;
NSLayoutConstraint* contentViewConstraint =
[NSLayoutConstraint constraintWithItem:firstItem
attribute:cellConstraint.firstAttribute
relatedBy:cellConstraint.relation
toItem:seccondItem
attribute:cellConstraint.secondAttribute
multiplier:cellConstraint.multiplier
constant:cellConstraint.constant];
[self.contentView addConstraint:contentViewConstraint];
}
}

You have taken a fix size UILable rather you have to use a dynamic size UILable.
Before that you need to calculate the size of text/string
#define FONT_SIZE 15.0f
#define LABEL_CONTENT_WIDTH 320.0f
#define LABEL_CONTENT_MARGIN 10.0f
NSString *text = #"YOUR TEXT HERE";
CGSize constraint = CGSizeMake(LABEL_CONTENT_WIDTH - (LABEL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height, 44.0f);
after calculating the size, apply them to your label like below
[labDetails setFrame:CGRectMake(labDetails.frame.origin.x, labDetails.frame.origin.y, labDetails.frame.size.width, MAX(height, 44.0f))];
And If you are using autolayout option then please check here: Link

Use Upper label frame's origin and size, and based on that set your detail labels frame, Use sizeToFit property of label.
Suppose 582,618 is your title label,
Like,
labDetails.frame=CGRectMake(5, title.frame.origin.x+title.frame.size.height+5, 300, 100);
[labDetails sizeToFit];

Related

How to programmatically sizeToFit width AND height on UILabel?

I'm programmatically creating multi-line UILabels ([label setNumberOfLines:0];).
The built-in sizeToFit method of UILabel works great for 1 line UILabels, but for multi-line text, it sets the height properly, but the width is set too small, causing longer text lines to wrap.
I don't know the label width until after the user enters their text. I want to resize the labels to fit the width of the longest line of text. And per #DonMag's comment, I also want to restrict the label to not be wider than the screen.
I tried different lineBreakMode settings but there isn't a 'nowrap' option.
I've searched SO and there are many related solutions but none that solve the problem of sizeToFit for both width and height.
Is there a way to programmatically size a multi-line UILabel to fit BOTH the width AND the height of the text?
You can do this with boundingRectWithSize...
Add your label to the view and give it a starting width constraint (doesn't really matter what value, as it will be changed).
Keep a reference to that width constraint (IBOutlet works fine if you're using IB).
Don't give it a height constraint.
When you set the text of the label, you can use this to change its width:
// get the font of the label
UIFont *theFont = _theLabel.font;
// get the text of the label
NSString *theString = _theLabel.text;
// calculate the bounding rect, limiting the width to the width of the view
CGRect r = [theString boundingRectWithSize:CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName: theFont}
context:nil];
// change the constant of the constraint to the calculated width
_theWidthConstraint.constant = ceil(r.size.width);
// NOTE: If you are *not* using auto-layout,
// this same calculation can be used to explicitly set
// the .frame of the label.
Edit:
As per the OP's requirement, a complete, runnable example -- using code only, no storyboards / IB -- can be found here: https://github.com/DonMag/MultilineLabelFitWidth
Edit 2:
GitHub project updated... now includes examples for both manual frame setting and auto layout / constraints.
With some more experimentation, I found something that does the trick that I have not seen in SO (yet...). In general it works like this:
Find the longest text line
Set numberOfLines to 1 (temporarily)
Set label text to longest text line
Call label.sizeToFit (sets label width for longest line)
Set numberOfLines to 0 (multi-line)
Set label text to full multi-line text
Call label.sizeToFit (sets label height for all lines)
Voila! Now your UILabel is sized to fit your multi-line text.
Here is an example (demo project on GitHub: UILabelSizeToFitDemo):
- (UILabel *)label = nil;
- (void)updateLabel:(NSString *)notes {
// close to the "sticky" notes color
UIColor *bananaColor = [ViewController colorWithHexString:#"#FFFC79"];
if (_label == nil) {
_label = [[UILabel alloc] init];
_label.numberOfLines = 0;
_label.textColor = UIColor.blackColor;
[_label setBackgroundColor:[bananaColor colorWithAlphaComponent:0.9f]];
_label.textAlignment = NSTextAlignmentLeft;
[self.view addSubview:_label];
}
// make font size based on screen size
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat fontSize = MIN(screenWidth,screenHeight) / 12;
[_label setFont:[UIFont systemFontOfSize:fontSize]];
// split lines
NSArray *lines = [notes componentsSeparatedByString:#"\n"];
NSString *longestLine = lines[0]; // prime it with 1st line
// fill a temp UILabel with each line to find the longest line
for (int i = 0; i < lines.count; i++) {
NSString *line = (NSString *)lines[i];
if (longestLine == nil || line.length > longestLine.length) {
longestLine = line;
}
}
// force UILabel to fit the largest line
[_label setNumberOfLines:1];
[_label setText:longestLine];
[_label sizeToFit];
// make sure it doesn't go off the screen
if (_label.frame.size.width > screenWidth) {
CGRect frame = _label.frame;
frame.size.width = screenWidth - 20;
_label.frame = frame;
}
// now fill with the actual notes (this saves the previous width)
[_label setNumberOfLines:0];
[_label setText:notes];
[_label sizeToFit];
// center the label in my view
CGPoint center = CGPointMake(self.view.bounds.size.width / 2, self.view.bounds.size.height / 2);
[_label setCenter:center];
}
UPDATE: Here is an alternate complete solution, using the boundinRectWithSize from the code snippet by #DonMag:
-(void)updateLabel:(NSString *)notes {
// close to the "sticky" notes color
UIColor *bananaColor = [ViewController colorWithHexString:#"#FFFC79"];
if (_label == nil) {
_label = [[UILabel alloc] init];
_label.numberOfLines = 0;
_label.textColor = UIColor.blackColor;
_label.backgroundColor = [bananaColor colorWithAlphaComponent:0.9f];
_label.textAlignment = NSTextAlignmentLeft;
[self.view addSubview:_label];
}
// set new text
_label.text = notes;
// make font size based on screen size
CGFloat screenWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat screenHeight = [UIScreen mainScreen].bounds.size.height;
CGFloat fontSize = MIN(screenWidth,screenHeight) / 12;
[_label setFont:[UIFont systemFontOfSize:fontSize]];
// calculate the bounding rect, limiting the width to the width of the view
CGRect frame = [notes boundingRectWithSize:CGSizeMake(self.view.frame.size.width, CGFLOAT_MAX)
options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading)
attributes:#{NSFontAttributeName: _label.font}
context:nil];
// set frame and then use sizeToFit
[_label setFrame:frame];
[_label sizeToFit];
// center the label in my view
CGPoint center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
[_label setCenter:center];
}

How to get a height a UITextView should be given width and length of text?

I am adding a UIView that contains a UITextView which is constrained to the top, left, and bottom of the view.
The width of the UIView should be the screen size's width which in turn will be the UITextView's width.
When I go to create this UIView, I can make it's CGSize to the screen size's width, but I am not sure on how to calculate the height.
How can I figure out what height I must set this UIView so that the UITextView can properly show? Is there a way I can figure out the number of lines a UITextView would have given a certain width?
You can use the following code to Get a dynamic Rect:
NSString *myDynamicString = #"Hello World!";
CGSize textRect = [myDynamicString boundingRectWithSize:CGSizeMake(MAX_WIDTH, MAX_HEIGHT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:[UIFont fontWithName:#"YouFontName" size:15]}
context:nil];
Note
MAX_WIDTH Width allowed to expand the rect. If you give 200 then the rect will exapand till 200 and then break and Vice Versa for MAX_HEIGHT
Use this code
CGSize constraintSize = CGSizeMake(textView.width - 2*textView.textContainer.lineFragmentPadding, CGFLOAT_MAX);
CGFloat messageTextViewHeight = [text boundingRectWithSize:constraintSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName: textView.font}
context:nil].size.height;
-(CGSize)getSizeForText:(NSString *)text maxWidth:(CGFloat)width font:(NSString *)fontName fontSize:(float)fontSize
{
CGSize constraintSize;
constraintSize.height = MAXFLOAT;
constraintSize.width = width;
NSDictionary *attributesDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
[UIFont fontWithName:fontName size:fontSize], NSFontAttributeName,
nil];
CGRect frame = [text boundingRectWithSize:constraintSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributesDictionary
context:nil];
CGSize stringSize = frame.size;
return stringSize;
}
First of all if you are using auto-layout this will be done out of the box, you don't have to do anything just setup constraints of auto-layout properly.
NSSString API is not very handy (as you can see in other answers) it is easy to miss something. I prfer use -(CGSize)sizeThatFits: from UIView.
UIView *textView = self.textView;
CGSize fitSize = { CGRectGetWidth(textView.frame), CGFLOAT_MAX };
CGSize fitSize = [textView sizeThatFits: fitSize];
NSLog(#"Your desired height: %f", fitSize.height);
It is more reliable and it should take into account all properties of text inside UITextView. I used this for UILabel didn't test for UITextView but it should work nicely.
If you want to see all the text in the text view an have the surrounding views around it adapt to contain it the easiest way would be to use a UILabel instead. Then you could just use constraints with priorities. Set the UILabel number of lines to 0 so that it automatically wraps. Then set the contentCompressionResistancePriority to 1000 for vertical axis. Then you don't need to worry about the sizes. Let autolayout do the work for you.

Why is so much extra space being added to my UILabel when I try to change height to fit text?

I have no idea why the height of my UILabel is expanding to such a great height. It leaves the text of my UILabel in the centre. I don't want all of this extra space...
Unwanted extra space
Here is my code (I set the text before this point):
self.infoDescription.numberOfLines = 0;
[self.infoDescription sizeToFit];
self.infoDescription.frame = CGRectMake(20, self.infoAdultSize.frame.size.height+self.infoAdultSize.frame.origin.y+10, self.infoView.frame.size.width-40, self.infoDescription.frame.size.height);
Please help :( I just want the height of the UILabel to fit the text exactly.
First set the frame and then make size to fit of label.
**self.infoDescription.frame = CGRectMake(20, self.infoAdultSize.frame.size.height+self.infoAdultSize.frame.origin.y+10, self.infoView.frame.size.width-40, self.infoDescription.frame.size.height);
[self.infoDescription sizeToFit];**
Try this:
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *myString = #"This is a long string which wraps";
UIFont *myFont = [UIFont fontWithName:#"Helvetica" size:14];
CGSize myStringSize = [myString sizeWithFont:myFont
constrainedToSize:maximumSize
lineBreakMode:self.myLabel.lineBreakMode];
(original source)
Please check this answer it works for me and it is exactly what you are looking for.
//Calculate the expected size based on the font and linebreak mode of your label
// FLT_MAX here simply means no constraint in height
CGSize maximumLabelSize = CGSizeMake(296, FLT_MAX);
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;

UILabel.frame.size.height shows less height than actual value

I am creating a UILabel with dynamic height by calculating the length of the text with this code:
UILabel *bankFullName = [[UILabel alloc] init];
[bankFullName setLineBreakMode:NSLineBreakByWordWrapping];
[bankFullName setMinimumScaleFactor:1];
[bankFullName setNumberOfLines:0];
[bankFullName setFont:[UIFont systemFontOfSize:13]];
CGSize constraint1 = CGSizeMake(240.0f, 20000.0f);
CGSize size1 = [[bankDetail valueForKey:#"FullName"] sizeWithFont:[UIFont systemFontOfSize:13] constrainedToSize:constraint1 lineBreakMode:NSLineBreakByWordWrapping];
bankFullName.text = [bankDetail valueForKey:#"FullName"];
CGRect fullnameFrame = CGRectMake(15.0, 15.0, 240.0, size1.height);
bankFullName.frame = fullnameFrame;
Now I don't have any issue with the code and the label is perfect.
The problem is when I log bankFullName.frame.size.height, the height is not right. If the label has two lines, it gives the height of the label having one line and so on.
Any idea on how to get the accurate height of the label or if something I'm doing is wrong?
Thanks
Just log the height of label in this method as -[UIView layoutSubviews] get called when the size of the any view changes:-
-(void)layoutSubviews
{
[super layoutSubviews];
NSLog(#""... // log your label height to get the exact value.
}
Do not use sizeWithFont: to change the height of your label.
Use [bankFullName sizeToFit] instead. And don't forget to set the maximum number of lines to more than one.
You should use sizeThatFits: to get correct size for UILabel, because sizeWithFont and boundingRectWithSize:options:attributes:context don't include UILabel padding.
CGFloat height = [self.bankFullName sizeThatFits:CGSizeMake(240, MAXFLOAT)].height;
self.bankFullName.frame = CGRectMake(15, 15, 240, height);

Get the exact size of UITextView with sizeWithAttribute

I have a UISlider that changes the font size of a UITextView. Before changing the font size, I would like to check if the height of my UITextView will be inferior to the height of its view container. The problem is that sizeToFit and sizeWithAttribute are returning different heights for the same font size.
To do that i'm trying to get the height of my UITextView with a custom fontSize, but i cannot figure out a way to do so, and don't understand why I don't get the same height when I do:
self.photoDescription.text = #"Test"
self.photoDescription.font = [self.photoDescription.font fontWithSize:18];
[self.photoDescription sizeToFit];
NSLog(#"real height %f", self.photoDescription.frame.size.height);
//getting : 37.5
and:
NSLog(#"calculated height %f", [self.photoDescription.text sizeWithAttributes:#{NSFontAttributeName:[self.photoDescription.font fontWithSize:18]}].height);
//getting: 20.97
same thing for:
CGRect textRect = [self.photoDescription.text boundingRectWithSize:CGSizeMake(320, 300)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:[self.photoDescription.font fontWithSize:18]}
context:nil];
CGSize size = textRect.size;
NSLog(#"height %f", size.height);
// getting : 20.97
Any thoughts on this?
I finally found an answer to my question with Jordan Montel Solution:
iOS7 UITextView contentsize.height alternative
I used his function to get the width :
- (CGFloat)textViewHeightForAttributedText:(NSAttributedString *)text andWidth:(CGFloat)width
{
UITextView *textView = [[UITextView alloc] init];
[textView setAttributedText:text];
CGSize size = [textView sizeThatFits:CGSizeMake(width, FLT_MAX)];
return size.height;
}

Resources