Custom UILabel width based on text length programatically - ios

I would like to create a UILabel that is a little bit wider than the width of the text in the same UILabel. I checked a lot of questions and tried the answers from them, but still can't find the right way. I can get the width of the text, but can't redrawn the frame.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *Cell = #"cell";
LikeActivityTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Cell];
cell.lbl.backgroundColor = [UIColor colorWithRed:7.0 green:4.0 blue:55.0 alpha:0.7];
NSString *lblString = [NSString stringWithFormat:#"%#", object[#"content"]];
cell.lbl.text = lblString;
float widthIs = [cell.lbl.text
boundingRectWithSize:cell.lbl.frame.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{ NSFontAttributeName:cell.lbl.font }
context:nil]
.size.width;
float heightIs =
[cell.lbl.text
boundingRectWithSize:cell.lbl.frame.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{ NSFontAttributeName:cell.lbl.font }
context:nil]
.size.height;
NSLog(#"CELL TEXT WIDTH %f", widthIs);
int x = widthIs + 10;
int y = heightIs;
// ATTEMPT 1
[cell.lbl setFrame:CGRectMake(0,0,x,cell.lbl.frame.origin.y)];
// ATTEMPT 2
cell.lbl.frame = CGRectMake(0, 0, x, cell.lbl.frame.origin.y);
return cell;
}
When I run these lines nothing happens, the label doesn't change that I can't understand because it should.

You can have the width of the label wrap around the text with just auto layout. If the text is only one line and you want the label size to fit around that, all you have to do is add a constraint that sets the leading attribute or center X (and constraints for the top/Center Y and height) and make sure you add
[yourLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
[yourLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
after adding it to the subview. If the text is multiline or could be multiline you will need a few more lines of code. You will need to set the compression resistance and hug for the vertical axes,
[yourLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[yourLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
Also add
- (void)layoutSubviews {
if (!CGRectIsEmpty(self.frame)) {
_featureDescriptionLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.contentView.frame)-59-5;
}
[super layoutSubviews];
}
This goes inside your custom table view cell. Set the max layout width to the widest width the text can be inside of your cell.
Also if it is multiline don't forget to set the number of lines to 0.

There is a very good tutorial for calculation of dynamic height of tableView based on its content. Here the UILabel is extended/customized to fit the dynamic content.
http://www.raywenderlich.com/73602/dynamic-table-view-cell-height-auto-layout

Frame setting is not effective because auto layout is on, try to set translatesAutoresizingMaskIntoConstraints property of the label to YES when you set its frame, or you can just turn off auto layout. And
[cell.lbl setFrame:CGRectMake(0,0,x,cell.lbl.frame.origin.y)]; should be
[cell.lbl setFrame:CGRectMake(0,0,x, heightIs)];

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGSize itemTextSize = [#"label text which you want to set" boundingRectWithSize:CGSizeMake(100, 30) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName : [UIFont fontWithName:#"Helvetica Neue" size:12.5]} context:nil].size;
return itemTextSize.height + 10;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = (UITableViewCell *)[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
CGSize itemTextSize = [#"label text which you want to set" boundingRectWithSize:CGSizeMake(100, 30) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName : [UIFont fontWithName:#"Helvetica Neue" size:12.5]} context:nil].size;
itemTextSize.width = itemTextSize.width + 10;
[cell.lbl setFrame:CGRectMake(0, 0, itemTextSize.width, itemTextSize.height)];
return cell;
}

Try below methods for cellForRow and for getting size of your text. Hope this will work for you.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString* cellIdentifier = #"CellIdentifier";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
cell.selectionStyle=UITableViewCellSelectionStyleNone;
UILabel *lblComment;
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
lblComment=[[UILabel alloc] init];
lblComment.backgroundColor=[UIColor clearColor];
lblComment.font=[UIFont fontWithName:FONT_NAME size:FONT_SIZE];
lblComment.numberOfLines=0;
lblComment.lineBreakMode=NSLineBreakByWordWrapping;
[cell.contentView addSubview:lblComment];
}else{
lblComment=(UILabel *)[[cell.contentView subviews] objectAtIndex:0];
}
lblComment.tag=[self realRowNumberForIndexPath:indexPath inTableView:tableView] + 0;
CGSize Comment_Size = [self GetLAbelSize:lblComment.text LabelFont:FONT_NAME width:FONT_SIZE];
lblComment.frame = CGRectMake(lblComment.frame.origin.x, lblComment.frame.origin.y, Comment_Size.width, Comment_Size.height);
return cell;
}
-(CGSize)GetLAbelSize:(NSString *)str_Text LabelFont:(UIFont *)font width:(float)width
{
CGSize constraintSize = CGSizeMake(width,MAXFLOAT);
// CGSize labelSize = [str_Text sizeWithFont:font constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];
CGRect boundingRect = [str_Text boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:font} context:nil];
CGSize labelSize = boundingRect.size;
return labelSize;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGSize lblComment = [self GetLAbelHeight:[array_Comment objectAtIndex:indexPath.row] LabelFont:FONT_NAME width:FONT_SIZE];
float totalHeight = lblComment.height+5;
return totalHeight;
}
- (NSInteger)realRowNumberForIndexPath:(NSIndexPath *)indexPath inTableView:(UITableView *)tableView
{
NSInteger retInt = 0;
if (!indexPath.section)
{
return indexPath.row;
}
for (int i=0; i<indexPath.section;i++)
{
retInt += [tableView numberOfRowsInSection:i];
}
return retInt + indexPath.row;
}
Regards.

Make a custom UITableViewCell. Let's call it CustomCell. Create a XIB, .h and .m for CustomCell. In the XIB, drag a table view cell out so that it is the only thing in the view. Add a label and whatever other views you wish into the cell. Add constraints to the views in whatever way makes sense, and make sure that one of those constraints is a width constraint on the label. Connect this constraint and the label to CustomCell.h. Your CustomCell.h will look like so:
#interface CustomCell : UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel *label;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelWidth;
#end
Now you can copy/paste the CustomCell from the XIB to the table you want to use the cell in. Then in your cellForRowAtIndexPath:, you can adjust the width of the label as follows, and the other views in the CustomCell will adjust accordingly (thanks, autolayout!).
CGSize size = [self.label sizeThatFits:CGSizeMake(self.frame.size.width, self.frame.size.height)];
self.labelWidth.constant = size.width;

Take a custom UITableViewCell class and setframe in its "layoutSubviews" method
`-(void)layoutSubviews {
[super layoutSubviews];
[self.lbl setFrame:...];
}`

The best way would be to apply proper auto layout constraints for the UILabel.Then if your target is iOS 8 , the set tableview's row height property to UITableViewAutomaticDimension.
or
set a height constraint to the tableview and in viewDidAppear
self.tableViewHeightConstraint.constant = self.tableView.contentSize.height;
in viewWillLayoutSubviews
get tableViewCell object
CGFloat width = label.bounds.size.width;
if ( label.preferredMaxLayoutWidth != width )
{
label.preferredMaxLayoutWidth = width;
[tableViewCell setNeedsLayout];
[tableViewCell layoutIfNeeded];
}
That should do the job if, your auto layout constraints are fine.

Create a fixed width and fixed height constraints on the label (via interface builder), expose them to the view controller (again, via interface builder), and manipulate the layoutconstraints directly:
// in the .h created by interface builder
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelWidth;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *labelHeight;
...
// in the implementation
[self.labelWidth setConstant:widthIs + 10];
[self.labelHeight setConstant:heightIs];

Assuming you create your custom cell like:
#implementation LikeActivityTableViewCell
-(id)init{
self = [super init];
if(self){
self.lbl = [[UILabel alloc] init];
self.lbl.font = [UIFont fontWithName:#"Arial" size:16]; // Set the font you want
self.lbl.backgroundColor = [UIColor colorWithRed:7.0/255 green:4.0/255 blue:55.0/255 alpha:0.7]; // Dont forget "/255"
[self.contentView addSubview:self.lbl];
}
return self;
}
#end
Then just try:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *Cell = #"cell";
LikeActivityTableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:Cell];
if(!cell){
cell = [[LikeActivityTableViewCell alloc] init];
}
cell.lbl.text = [NSString stringWithFormat:#"Am I cell number %d? No!", indexPath.row * 8]; // Put your text here
CGSize labelSize = [self getFrameForLabel:cell.lbl];
labelSize.width += 10.f;
cell.lbl.frame = CGRectMake(cell.contentView.frame.size.width * 0.5f - labelSize.width * 0.5f,
cell.contentView.frame.size.height * 0.5f - labelSize.height * 0.5f,
labelSize.width,
labelSize.height); // I decided to center the label but you can put 0, 0 as origin
return cell;
}
-(CGSize)getFrameForLabel:(UILabel*)label{
NSDictionary *attributes = #{NSFontAttributeName: label.font};
return [label.text sizeWithAttributes:attributes];
}

I managed to do a similar thing using CustomTableViewCell, by setting translatesAutoresizingMaskIntoConstraints of a UILabel property of a custom cell, to true, and then setting the frame of the label to whatever you want by calling customCell.frame = CGRectMake(what, ever, you, want). The only problem with this is that than you will get a warning saying "Unable to simultaneously satisfy constraints.", until you change translatesAutoresizingMaskIntoConstraints to false. This happens when you set your constraints manually through Visual Format. Not sure how to do it through AutoLayout. Im a beginner at this, but thought to share my findings with you anyway, hope it helps a bit. Cheers!

Check if this one helps..
UILabel *type;
type.frame=[self calculateHeightOfTextFromWidth:type withText:type.text];
-(CGRect) calculateHeightOfTextFromWidth:(UILabel*)detailLabel withText:(NSString*)text {
CGRect currentFrame = detailLabel.frame;
CGSize max = CGSizeMake(detailLabel.frame.size.width, 500);
CGSize expected = [text sizeWithFont:detailLabel.font constrainedToSize:max lineBreakMode:detailLabel.lineBreakMode];
currentFrame.size.height = expected.height;
return currentFrame;
}

Here's a method that should return the proper width of your UILabel width based on the height and text string. Set the cell frame with the width returned from this method.
CGFloat *maxWidth = the maximum width you would want your label to be
CGFloat *labelHeight = the height of your label
CGFloat *additionalWidthBuffer = any fixed extra width on your label
-(CGFloat)labelHeightForText:(NSString*) text
{
UIFont * font = [UIFont systemFontOfSize:15.0f];
CGFloat width = [text boundingRectWithSize:CGSizeMake(maxWidth, labelHeight) options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:#{NSFontAttributeName: font} context:nil].size.width;
return height + additionalWidthBuffer;
}

Related

How to increase label or text view size (height and width) in tableview by objective c(For Conversation Page) Can you Help me?

I can't Increase Label or Textview Size in table view by objective c.
I'm Struck for this problem.
Finally i found the answer with easy method using contraints(set maximum and minimum width and height for label)Thats the output
Adding up my code ..
#pragma mark - TABLE VIEW DELEGATE
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"ChatCell";
ChatCell *cell = (ChatCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[ChatCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
cell.txtView.text=[messages objectAtIndex:indexPath.row];
if(indexPath.row%2){
cell.txtView.backgroundColor=[UIColor whiteColor];
cell.leading.constant=0.0f;
}else{
cell.txtView.backgroundColor=[UIColor colorWithRed:246.0f/255 green:190.0f/255 blue:175.0f/255 alpha:1.0f];
cell.leading.constant=((tblView.frame.size.width)/2)-50-16;
}
[cell.subView.layer setShadowColor:[UIColor grayColor].CGColor];
[cell.subView.layer setShadowOpacity:1.0f];
[cell.subView.layer setShadowRadius:0.0f];
[cell.subView.layer setShadowOffset:CGSizeMake(0, 2.0)];
[cell.txtView.layer setCornerRadius:10.0f];
[cell.txtView.layer setMasksToBounds:YES];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *attributesName = #{NSFontAttributeName: [UIFont fontWithName:#".SFUIText-Regular" size:14.0f]};
CGRect r1 = [[messages objectAtIndex:indexPath.row] boundingRectWithSize:CGSizeMake((tblView.frame.size.width/2)+50, 0)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:attributesName
context:nil];
return r1.size.height+70;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [messages count];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
Adding the ChatCell properties list. Cell contains a subView and textview with in subview(top, leading, bottom, trailing of textview all connected to subview) and leading is the auto layout constraint connecting superview and subview leading end.
#property(nonatomic,weak) IBOutlet UITextView *txtView;
#property(nonatomic,weak) IBOutlet UILabel *lblDate;
#property(nonatomic,weak) IBOutlet UIView *subView;
#property(nonatomic,weak) IBOutlet NSLayoutConstraint *leading;
If you use textview
-(void)textView
{
CGFloat fixedWidth = textView.frame.size.width;
CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
CGRect newFrame = textView.frame;
newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);
NSLog(#"this is updating height%#",NSStringFromCGSize(newFrame.size));
height=newFrame.size.height;
}
Get the height from this method then set it to heightforrow method
Set constraints for the textview leading,trailing,top,bottom.

UITextView embedded in a UITableViewCell not resizing properly

Here is my code in the cellForRowAtIndexPath delegate:
Status *status = nil;
status = [myArray objectAtIndex:indexPath.row];
NSString* postvalue = status.statusContent;
cell.postContent.scrollEnabled = NO;
CGSize mysize = [postvalue sizeWithAttributes:#{NSFontAttributeName:[UIFont systemFontOfSize:17.0f]}];
CGRect frame = cell.postContent.frame;
frame.size.height = mysize.height;
cell.postContent.frame = frame;
cell.postContent.text = postvalue;
Where cell.postContent is a textView
And here is my code that resizes the cells:
-(CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
Status *status = nil;
status = [myArray objectAtIndex:indexPath.row];
NSString* postvalue = status.statusContent;
return 100 + [self heightForText:postvalue];
}
-(CGFloat)heightForText:(NSString *)text
{
NSInteger MAX_HEIGHT = 2000;
UITextView * textView = [[UITextView alloc] initWithFrame: CGRectMake(0, 0, 226, MAX_HEIGHT)];
textView.text = text;
textView.font = [UIFont systemFontOfSize:17.0f];// your font
[textView sizeToFit];
return textView.frame.size.height;
}
This is what it results in:
I have replaced the user name with the height calculated in the cellForRow.. delegate so you can see the height is being calculated correctly, and the cell is resizing correctly, but the textview is not - there are quite a few more lines than you can't see. Any ideas?
Thanks
That's because you shouldn't create new textField (which you also forgot to add as a subview) but resize the cell's outlet. Try to set textField's height in cellForRow when the cell is created
UITextView takes some default padding around it so this might be issue. Set contentInset of the UITextView by code.
// this is how we define setContentInset method
[textView setContentInset:UIEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right)];
// and you should do like this
[textView setContentInset:UIEdgeInsetsMake(-8, -8, -8 ,-8)];
u can access it's content view i think, here is the code,
i am using some values for testing it works fine, go through this hope helps u ... :)
disable auto layout for textfield
in CustomCelll.h file
#interface CustomCelll : UITableViewCell
//i think u hav an outlet for textview
#property (retain, nonatomic) IBOutlet UITextView *postContent;
#property (nonatomic,retain)NSString *message;//you get the message to set the height
in CustomCelll.m file
#implementation CustomCelll
#synthesize postContent;
#synthesize imageView;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//heare i am adding the button
UIFont *font = [UIFont systemFontOfSize:17.0f];
self.postContent.frame = CGRectZero;//initially set it zero
self.postContent.font = font;
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
CGSize size = [self findMessgeStringHeight];//you can ge the size
//set frame for ur label
self.postContent.frame = CGRectMake(103, 8, size.width + 10,size.height + 10);//set the height here(for your case) and disable auto layout
self.postContent.text = self.message;//set the message
}
- (CGSize)findMessgeStringHeight
{
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:self.message attributes:#{ NSFontAttributeName:[UIFont systemFontOfSize:17.0f] }];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){225, MAXFLOAT}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize requiredSize = rect.size;
return requiredSize; //finally u return your height
}
//in your controller
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCelll *cell = [tableView dequeueReusableCellWithIdentifier:#"BDCustomCell"];
if (cell == nil) {
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"Empty" owner:self options:nil];
cell = [topLevelObjects objectAtIndex:0];
}
cell.message = #"hello, how are u, it been so long since we met, how's the weather there, here too cold, i am going to my mom's home may be i will stay there for 2 or 3 weeks";
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *str = #"hello, how are u, it been so long since we met, how's the weather there, here too cold, i am going to my mom's home may be i will stay there for 2 or 3 weeks";//use same sring to get the height
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:str attributes:#{ NSFontAttributeName:[UIFont systemFontOfSize:17.0f]
}];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){225, MAXFLOAT}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize requiredSize = rect.size;
return requiredSize.height + 30;
}

Cannot change frame of a UILabel in a UITableViewCell when first appearing (using Autolayout)

I have a prototype cell inside my UITableView which contains a UILabel. I want to dynamically change the size of the label (and the cell) depending on the size of the text in the label.
I create the prototype cell in cellForRowAtIndexPath like this:
static NSString *CellIdentifier = #"ProgramDetailCell";
ProgramDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.descriptionLabel.text = self.program.subtitle;
return cell;
Then my ProgramDetailCell has the following implementation:
#implementation ProgramDetailCell
- (void)layoutSubviews {
[super layoutSubviews];
[self.descriptionLabel sizeToFit];
}
#end
The first time the cell is displayed, layoutSubviews is called, but the descriptionLabel does not get resized. However, if I scroll down the table and back up again, the "reused" cell appears with the label correctly resized!
Why does it not work the first time the cell is displayed - and what do I need to do to fix it.
Thanks in advance!
In xib, go to first tab, under Interface Builder Document , uncheck use Auto Layout box.
It doesn't work because you are using auto layout. You need some auto layout way to achieve this.
Here's the solution.
Step 1 :
Have the UILabel Pinned to Top and Bottom of the UITableViewCell. You can achieve this through the Interface Builder by having Vertical Constraint on UILabel from top and bottom of the cell. This will make the UILabel increase in height if the cell's height increase or vice versa.
Step 2:
In your UIViewController in - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath method calculate the size of the UITableViewCell.
You can calculate it using :
CGRect textFrame = [YourText boundingRectWithSize:CGSizeMake(width of the label, FLT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:Your Font} context:nil];
now return the textFrame.size.height + padding if present.
Step 3 :
You will achieve what you wanted --- "dynamically change the size of the label (and the cell) depending on the size of the text in the label" after compiling and running even for the first time.
After retrieving all data from server you can get height of that UILabel using this method.
CGSize maximumSize = CGSizeMake(210, 9999);
for (int i = 0; i < [_arrProductList count]; i++) {
float row_height = 0.0f;
ProductInformation *product_obj = [_arrProductList objectAtIndex:i];
CGSize desc_size = [self measureHeightForText:product_obj.product_desc forFont: [UIFont systemFontOfSize:14] forSize:maximumSize];
row_height = row_height + desc_size.height;
// [_arrRowHeights addObject:[NSString stringWithFormat:#"%f", row_height]]; You can take it into array.
}
[tableView reloadData];
And here i have given description of measureHeightForText:. This logic is working in all iOS5,iOS6,iOS7.
-(CGSize)measureHeightForText:(NSString *)strText forFont:(UIFont *)font forSize:(CGSize)size{
if (!testingLabel) {
testingLabel = [[UILabel alloc] init];
// testingLabel.font = [UIFont fontWithName:[AppHandlers zHandler].fontName size:16];
testingLabel.text = #"";
testingLabel.numberOfLines = 0;
}
testingLabel.text =strText;
testingLabel.font = font;
CGSize expectedSize = [testingLabel sizeThatFits:size];
return expectedSize;
}
And then update size of your label according it. This is working fine for me. I am using it.
Because when layoutSubviews is called your descriptionLabel's text is not set yet. And when you scroll, the text is set. So it is correct now.
I suggest you call sizeToFit after you set the text.
static NSString *CellIdentifier = #"ProgramDetailCell";
ProgramDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.descriptionLabel.text = self.program.subtitle;
[cell.descriptionLabel sizeToFit];
return cell;
Call this in heightForRowAtIndexPath and manually calculate the height
static NSString *CellIdentifier = #"ProgramDetailCell";
ProgramDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.descriptionLabel.text = self.program.subtitle;
[cell.descriptionLabel sizeToFit];
return cell.descriptionLabel.frame.size.height+cell.descriptionLabel.frame.origin.y;
You can use below code:
//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;
If your requirement is dynamically changing label height mean follow the below link. When we need to change height of label we need to change the row height also:
Resizing UILabel not quite working
Use below code for dynamic height set in cell
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *messagetext=[NSString stringWithFormat:#"%#",[[arryStoryView objectAtIndex:indexPath.row] valueForKey:#"messagetext"]];
CGSize StoryTextSize= [messagetext sizeWithFont:[UIFont fontWithName:#"Georgia" size:17.0f] constrainedToSize:CGSizeMake(300, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
int TotalHeight;
TotalHeight= StoryTextSize.height + 10;
return TotalHeight;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell1";
UITableViewCell *cell=[tblSendMsg dequeueReusableCellWithIdentifier:CellIdentifier];
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
NSString *storytext=[NSString stringWithFormat:#"%#",[[arryStoryView objectAtIndex:indexPath.row] valueForKey:#"storytext"]];
CGSize StoryTextSize = [storytext sizeWithFont:[UIFont fontWithName:#"Georgia" size:17.0f] constrainedToSize:CGSizeMake(300, MAXFLOAT) lineBreakMode:NSLineBreakByWordWrapping];
lblStoryText.frame=CGRectMake(5, 25, [[UIScreen mainScreen] bounds].size.width-10, StoryTextSize.height+30);
int nooflines=StoryTextSize.height/16;
int i= StoryTextSize.height;
if(i%16 !=0)
{
nooflines=nooflines+1;
}
lblStoryText.numberOfLines=nooflines;
lblStoryText.font=[UIFont fontWithName:#"Georgia" size:17.0f];
lblStoryText.text=[NSString stringWithFormat:#"%#",storytext];
return cell;
}
If you are using autolayout, modifying the frame will have no effect.
Instead, you should modify the constraints.

UILabel doesn't change height in UITableViewCell in first scroll

I'm using tableview on storyboard.
I change label's frame in (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath function.
then, after some scrolling, it can change frame. but, when I open my application, frame doesn't change at first.
sorry, can't post image till 10 reputation.
please help.
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// get one row
Plan* planObj = [_planObjList objectAtIndex:indexPath.row];
// get custom cell info
LargeImageCell* cell = (LargeImageCell*)[tableView dequeueReusableCellWithIdentifier:#"CustomLargeImageCell"];
cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"bg"]];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.titleLabel.text = planObj.planTitle;
cell.titleLabel.numberOfLines = 0;
cell.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.userNameLabel.text = planObj.getProducerName;
// title size
CGSize titleSize = [cell.titleLabel.text boundingRectWithSize:CGSizeMake(300.0f, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin) attributes:#{NSFontAttributeName: cell.titleLabel.font} context:nil].size;
// user name size
CGSize userNameSize = [cell.userNameLabel.text boundingRectWithSize:CGSizeMake(300.0f, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin) attributes:#{NSFontAttributeName: cell.userNameLabel.font} context:nil].size;
// set title size
cell.titleLabel.frame = CGRectMake(7.0f, 230.0f, 306.0f, ceilf(5.0f + titleSize.height));
cell.titleLabel.backgroundColor = [UIColor redColor];
// set name size
cell.userNameLabel.frame = CGRectMake(7.0f, ceilf(235.0f + titleSize.height), 148.0f, ceilf(5.0f + userNameSize.height));
cell.userNameLabel.backgroundColor = [UIColor blueColor];
}
autolayout was problem.
I switched off 'Use Autolayout' on storyboard. then, it became clear.
thank you all.
If your app is using Autolayout you should do it with Constraints. To resize a UILabel with Constraints that should has at least that properties:
Line Numbers = 0
Line Breaks = Word Wrap
And about Constraints you should set in both sides, and one to top, DONT set to bottom!!
To set right size in the row u can use this code example:
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
id data = [self.listOfNews safeObjectAtIndex:indexPath.row];
UIFont *font = [UIFont fontWithName:K_FONT_AVENIR_MEDIUM size:textSize];
if ([data isKindOfClass:[NewsModel class]]) {
NewsModel *news = (NewsModel *)data;
if (SYSTEM_VERSION_LESS_THAN(#"7.0")) {
CGSize constraintSize = CGSizeMake(cellTextWidth, MAXFLOAT);
CGSize textRect = [news.title sizeWithFont:font constrainedToSize:constraintSize];
return textRect.height + paddingTopAndBottom;
} else {
CGRect textRect = [news.title boundingRectWithSize:CGSizeMake(cellTextWidth, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:font}
context:nil];
return textRect.size.height + paddingTopAndBottom;
}
}
return 0;
}
Try resizing frames in willDisplayCell delegate method.
You can't change the size initially through cellForRow method. You need to calculate the size and return it in the following delegate
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
To calculate size for a label based on the text use
NSString *labelText=#"some text";
[myLabel setText:labelText];
UIFont *labelTextFont = [UIFont fontWithName:#"Helvetica" size:labelTextsize];
CGSize labelFrameSize = [labelText sizeWithFont:labelTextFont];
myLabel.frame = CGRectMake(xPos, yPos, labelFrameSize.width, labelFrameSize.height);
Remember these steps in order to have UILabel to change size:
1) If you have a Custom UITableViewCell, switch off AutoLayout on elements of the cell
2) Use heightForRowAtIndex protocol method to change the height
3) Set the numberOfLines = 0 for the UILabel inside the cell
4) If this does not work re-set the frame ( I found that this happens when you are trying to enlarge a UILabel in some "far" end of the cell)
Examples
- (UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
GeneralCell* cell = [tableView dequeueReusableCellWithIdentifier:#"GeneralCell"];
if (cell == nil) {
cell = [[GeneralCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"GeneralCell"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
/////// USE the following block if still in trouble
CGRect frame = cell.label.frame;
[cell.label setFrame:frame];
[cell.label sizeToFit]; // this should not be necessary in general
///////////
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *detail = [NSString stringWithFormat:#"YOUR TEXT]];
CGSize constraintSize = CGSizeMake(CELL_CONTENT_WIDTH, MAXFLOAT);
CGSize labelSize = [detail boundingRectWithSize:constraintSize
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:FONT_SIZE]}
context:nil].size;
float h = (fmod((int)labelSize.height ,2) == 0) ? labelSize.height : labelSize.height+1;
CGFloat height = MAX(h, 30.0f);
elemento = nil;
detail = nil;
return height + (CELL_CONTENT_MARGIN * 2);
}

ios - trying to understand how cellForRowAtIndexPath and heightForRowAtIndexPath work when dealing with UITableViewCells

With the help of the good people of StackOverflow, I have these two methods:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)
reuseIdentifier:#"business"];
NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(#"comment")];
NSLog(businessPrivacy);
// FIND IF THE BUSINESS PLAN IS PRIVATE OR NOT.
CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f);
CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, MAX(size.height, 44.0f) + 20.0f)];
label.numberOfLines = 0;
label.lineBreakMode = UILineBreakModeWordWrap;
label.text = comment;
[cell.contentView addSubview:label];
return cell;
}
//Cell size for word wrapping.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(#"comment")];
CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f);
CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = MAX(size.height, 44.0f);
return height + (10 * 2);
}
The effect that they have is reducing font size from default font size, and dynamically resizing to ALMOST fit the entire text of a comment no matter how long that text might be.
What I am confused with is that I have some of the same code in both methods, and I dont know how it really should look like. I do know both methods are getting called, but not sure what should be where so they would work properly.
Thanks in advance for advice.
It looks like you need them in both. I have rewritten your code with comments so that you can make sense of it:
//This function is used to create the cell and the content of the cell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//Here you are allocating a new cell with a reuse identifier. This is only needed if
//you plan on reusing the cells and using [tableView dequeueReusableCellWithIdentifier:cellIdentifier]
//Reusable cells will save you some memory and make your tableview work more smoothly,
//however here you are not selecting from the reusable pool, and are instead making a new cell each time
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)
reuseIdentifier:#"business"];
//This is pulling the text for the comment, it is obviously necessary
NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(#"comment")];
NSLog(businessPrivacy);
// FIND IF THE BUSINESS PLAN IS PRIVATE OR NOT.
// This is creating a constraint size for the label you are making
CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f);
// This is determining the size that you will need for the label based on the comment
// length and the contraint size
CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
// Here you are creating your label and initializing it with the frame that you have
// determined by your size calculations above
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, MAX(size.height, 44.0f) + 20.0f)];
// setting up the label properties
label.numberOfLines = 0;
label.lineBreakMode = UILineBreakModeWordWrap;
label.text = comment;
// adding the label view to the cell that you have created
[cell.contentView addSubview:label];
// return the cell for the table view
return cell;
}
//Cell size for word wrapping.
//This method will determine how tall each row needs to be.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
//Here you are getting the comment again. This is necessary to determine how tall you need
//the cell to be
NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(#"comment")];
// Again you are getting the constraints because you are going to us this size
// to constrain the height of the cell just like you determined the size for the label.
CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f);
// Again, determining the size that we will need for the label, because it will drive
// the height of the cell
CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
// Finally, we can determine the height for the cell!
CGFloat height = MAX(size.height, 44.0f);
// return the height, which is the height of the label plus some extra space to make
// it look good.
return height + (10 * 2);
}
So basically, the cellForRow... function creates the content of the cell and the heightForRow... function determines the height. You need all of that information in both of them because the cell function only creates the content of the cell while the height function creates the height of the row and the comment, constraint, and size are all important in determine the label size for the cell content and the height of the cell.
So heightForRowAtIndexPath, as its name suggests, only deal with the height of the cells. i.e. the return value (a CGFloat) of that function is the height of the cell at the specified indexpath.
cellForRowAtIndexPath on the other hand sets up the actual cell, including all its subviews. What happens is, say some cells have a 5-line UILabel and some have 1-line. Then You need to adjust the size of the cell in heightForRowAtIndexPath, but at the same time you also need to adjust the size of the UILabel within the cell in cellForRowAtIndexPath. The latter will not automatically happen. You need to take care of both yourself.
If you have to write the same code two or more times, you should consider extracting the duplicate code into a method or function. But you have some other problems we should address.
Let's declare some constants so we don't have to repeat numbers all over the code:
static const CGFloat kLabelMargin = 10.0f;
static const CGFloat kLabelWidth = 320.0f - 2.0f * kLabelMargin;
One line you have duplicated in both methods looks up the comment for a row. Let's make a method to do that:
- (NSString *)commentForRowAtIndexPath:(NSIndexPath *)indexPath {
return [[items_array objectAtIndex:[indexPath row]] objectForKey:#"comment"];
}
The other duplicated code computes the height of the row, so let's make a function to return that:
static CGFloat heightForComment(NSString *comment) {
CGSize constraint = CGSizeMake(kLabelWidth, 20000.0f);
CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
return MAX(size.height, 44.0f) + 2.0f * kLabelMargin;
}
Now we can rewrite your tableView:heightForRowAtIndexPath: method:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return heightForComment([self commentForRowAtIndexPath:indexPath]);
}
Finally, let's rewrite your tableView:cellForRowAtIndexPath: method. We will make it properly reuse cells (to avoid wasting memory), and we'll make it use the new method and function we created.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *const kReuseIdentifier = #"business";
static const NSInteger kLabelTag = 1;
NSLog(#"%#", businessPrivacy);
// FIND IF THE BUSINESS PLAN IS PRIVATE OR NOT.
NSString *comment = [self commentForRowAtIndexPath:indexPath];
CGRect labelFrame = CGRectMake(0, 0, kLabelWidth, heightForComment(comment));
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kReuseIdentifier];
UILabel *label;
if (cell) {
label = (UILabel *)[cell.contentView viewWithTag:kLabelTag];
label.frame = labelFrame;
} else {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kReuseIdentifier];
label = [[UILabel alloc] initWithFrame:labelFrame];
label.tag = kLabelTag;
label.numberOfLines = 0;
label.lineBreakMode = UILineBreakModeWordWrap;
[cell.contentView addSubview:label];
}
label.text = comment;
return cell;
}

Resources