UITextView embedded in a UITableViewCell not resizing properly - ios

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

Related

How to Increase TableCell Height When Content Added Programmatically?

I am Developing an app. I have some data which is coming from server.
Now I Have no Idea about the data count for rows. I only Know the name of Fields.
I want To show these data in UITableViewCell.
I have a custom TableCell. I have taken a ContentView inside it.
I have set the following constraint:
- Leading
- Trailing
- Top
- Bottom
In My ViewController's DidLoad Method I have this Code:
UINib *nib = [UINib nibWithNibName:cellName bundle:nil];
[[self mTableView] registerNib:nib forCellReuseIdentifier:cellName];
self.mTableView.rowHeight = UITableViewAutomaticDimension;
self.mTableView.estimatedRowHeight = 100.0;
I am creating UILabel Like this
- (void)awakeFromNib {
[super awakeFromNib];
CGFloat ypos = 0;
for(int i=0;i<6;i++)
{
UILabel *lbl = [[UILabel alloc]init];
lbl.backgroundColor= [UIColor redColor];
lbl.frame = CGRectMake(0,ypos,30,10);
[self addSubview:lbl];
ypos += 16;
}
[self setNeedsLayout];
[self layoutIfNeeded];
// Initialization code
}
This is my CustomCell.But my TableCell Hegiht is not Increasing.
Please anyone suggest me what is i am missing ?
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *dict1 = (NSDictionary*)[array objectAtIndex:indexPath.row];
NSString *cellText = [dict1 valueForKey:#"test"];
UIFont *cellFont = [UIFont fontWithName:FONT_NAME_GOTHAM_4 size:11.0];
CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT);
CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping];
return labelSize.height + 80;
}
You are doing right, so far. But do not forget to use the delegate/data source of your tableView - cellForRowHeight.
Also, as Lion have mentioned, you need to add constraints to your labels. If you do your label programmatically, then do the autolayout programmatically as well.

Counting UITableView ContentView height is not always correct

I'm creating a messenger app, which displays a dialog between two people.
Parsing API response, I got text for inbox and outbox messages. Then I create a cell, using a UITableViewCell prototype from the storyboard.
All constraints are adjusted correctly.
The problem is that I use
[self.tableView scrollToRowAtIndexPath:lastIndexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];
to scroll the tableView to the bottom to have the last message in focus but the contentView of the upper cells is not counted at this time.
So i had to count height of cell before it is displayed. For this i use
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
RJMessageCell *cell = [self configureBasicCellAtIndexPath:indexPath];
[cell setNeedsLayout];
[cell layoutIfNeeded];
CGSize maximumSize = CGSizeMake(320.0, UILayoutFittingCompressedSize.height);
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:maximumSize].height;
return height;
}
- (RJMessageCell *)configureBasicCellAtIndexPath:(NSIndexPath *)indexPath {
static NSString *inboxIdentifier = #"Inbox";
static NSString *outboxIdentifier = #"Outbox";
NSString *identifier;
RJMessage *message = [[[self.messageSectionsArray objectAtIndex:indexPath.section] messages] objectAtIndex:indexPath.row];
if (message.messageIsMine) {
identifier = outboxIdentifier;
} else {
identifier = inboxIdentifier;
}
RJMessageCell *cell = [self.tableView dequeueReusableCellWithIdentifier:identifier];
cell.messageView.layer.cornerRadius = 10.f;
cell.messageView.clipsToBounds = YES;
if ([message.text isEqualToString:#""]) {
cell.messageTextLabel.text = #" ";
} else {
cell.messageTextLabel.text = message.text;
}
cell.messageTextLabel.numberOfLines = 0;
cell.messageTextLabel.lineBreakMode = NSLineBreakByWordWrapping;
cell.timeLabel.text = [self stringTimeFromTimeInterval:message.messageInterval];
if (message.messageState == RJMessageStateUnread) {
cell.backgroundColor = [UIColor colorWithRed:151/255.0 green:200/255.0 blue:255/255.0 alpha:0.4];
} else {
cell.backgroundColor = [UIColor clearColor];
}
return cell;
}
Also the UILabel on screenshots are custom, to setBounds to label
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
if (self.numberOfLines == 0 && bounds.size.width != self.preferredMaxLayoutWidth) {
self.preferredMaxLayoutWidth = self.bounds.size.width;
[self setNeedsUpdateConstraints];
}
}
And the last thing i do, adding estimatedRowHeight in viewDidLoad
self.tableView.estimatedRowHeight = self.tableView.rowHeight;
self.tableView.rowHeight = UITableViewAutomaticDimension;
The first time they appear everything looks good, but when I scroll the table up and down, my cells change their size randomly.
What's wrong with the cell height?
You have to return Height by calculating the text width & height which you want to place inside the cell.
//Height For Row at index path
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellText = [NSString stringWithFormat:#"%#",[arrDataSource[indexPath.row]]];
UIFont *cellFont = [UIFont fontWithName:#"Helvetica" size:15.0];
NSAttributedString *attributedText =
[[NSAttributedString alloc]
initWithString:cellText
attributes:#
{
NSFontAttributeName: cellFont
}];
CGRect rect = [attributedText boundingRectWithSize:CGSizeMake(tableView.bounds.size.width - 90.0, CGFLOAT_MAX)
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
return rect.size.height + 42;
}

Custom UILabel width based on text length programatically

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

UITableView cell contents not displayed properly

I use auto layout and want to display UITableView with custom cell that has a UITextView with variable content.
Cells are displayed as shown below. For chat message, when cell is first displayed only 2-3 characters are displayed in a single line and next characters are forced to go to next line. But when I scroll tableView so that these cells are not visible and scroll back to make them visible (I do this so that when they are visible again cellForRowAtIndexPath: method is called again to render the cell), they render the cell properly as shown in second image.
Code :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [chatData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RS_User *user = [[RS_User alloc]init];
chatCell *cell = (chatCell *)[tableView dequeueReusableCellWithIdentifier:CHAT_CELL_IDENTIFIER];
NSUInteger row = indexPath.row;
cell.chatCellBackground.image = nil;
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:TEXT]; // get text string(message) from array
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIFont *font = [UIFont systemFontOfSize:FONT_SIZE];
cell.textString.font = [UIFont fontWithName:FONT_NAME size:FONT_SIZE]; // set text font
cell.textString.text = chatText;
// set text
CGSize size = [cell.textString.text sizeWithFont:cell.textString.font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
cell.textString.frame = ...;
[cell.textString sizeToFit];
NSDate *theDate = [[chatData objectAtIndex:row] objectForKey:DATE];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:DATE_FORMAT];
NSString *timeString = [formatter stringFromDate:theDate];
cell.timeLabel.text = timeString; // set timeLabel to display date and time
cell.timeLabel.font = [UIFont fontWithName:FONT_NAME size:SMALL_FONT_SIZE];
cell.userLabel.text = #"Name";//[[chatData objectAtIndex:row] objectForKey:NAME]; // set userLabel to display userName
CGSize size1 = [cell.userLabel.text sizeWithFont:font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
// check cell contains sender name or receiver name
if (thisCellIsForSender)
{
// Set bubble for sender
cell.chatCellBackground.image = [[UIImage imageNamed:#"bubbleMine.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
}
else
{
// set bubble for receiver
cell.chatCellBackground.image = [[UIImage imageNamed:#"bubbleSomeone.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
}
[cell setNeedsLayout];
[cell layoutIfNeeded];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
RS_User *user = [[RS_User alloc]init];
chatCell *cell = (chatCell *)[tableView dequeueReusableCellWithIdentifier:CHAT_CELL_IDENTIFIER];
NSUInteger row = indexPath.row;
cell.chatCellBackground.image = nil;
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:TEXT]; // get text string(message) from array
cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping;
UIFont *font = [UIFont systemFontOfSize:FONT_SIZE];
cell.textString.font = [UIFont fontWithName:FONT_NAME size:FONT_SIZE]; // set text font
cell.textString.text = chatText;
// set text
CGSize size = [cell.textString.text sizeWithFont:cell.textString.font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
cell.textString.frame = ...;
[cell.textString sizeToFit];
NSDate *theDate = [[chatData objectAtIndex:row] objectForKey:DATE];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:DATE_FORMAT];
NSString *timeString = [formatter stringFromDate:theDate];
cell.timeLabel.text = timeString; // set timeLabel to display date and time
cell.timeLabel.font = [UIFont fontWithName:FONT_NAME size:SMALL_FONT_SIZE];
cell.userLabel.text = [[chatData objectAtIndex:row] objectForKey:NAME]; // set userLabel to display userName
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
CGSize size1 = [cell.userLabel.text sizeWithFont:font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
// check cell contains sender name or receiver name
if (thisCellIsForSender)
{
// Set bubble for sender
cell.chatCellBackground.image = [[UIImage imageNamed:#"bubbleMine.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
}
else
{
// set bubble for receiver
cell.chatCellBackground.image = [[UIImage imageNamed:#"bubbleSomeone.png"] stretchableImageWithLeftCapWidth:STRETCHED_WIDTH topCapHeight:STRETCHED_HEIGHT];
cell.chatCellBackground.frame = ...;
}
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));
[cell setNeedsLayout];
[cell layoutIfNeeded];
return cell.bounds.size.height;
}
UPDATE : I could solve some of the issues from coverback's answer. Still cell is not laid out correctly. I am adding photos for constraints of each UI object in cell.
User name :
Time stamp :
Chat message :
Bubble image :
Cell Layout :
Cell height in cellForRowAtIndexPath: is always 100 even though I return different value from heightForRowAtIndexPath: method. Cell height in storyboard is 100.
Chat message in third cell is clipped from bottom.
Time stamps and chat message labels are some time not aligned properly to each other even though both have constraint vertical spacing from username label.
Username label in third cell is vanished.
Do you see anything wrong in constraints? You can ask me if analyzing constraints is difficult.
Combining the answers by thandasoru and coverback solved my issue. Below is the code I use.
I added below method in custom UITableViewCell's class.
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat maxTextWidth = [UIScreen mainScreen].bounds.size.width * 0.40;
self.userLabel.preferredMaxLayoutWidth = maxTextWidth;
self.chatMessage.preferredMaxLayoutWidth = maxTextWidth;
self.timeLabel.preferredMaxLayoutWidth = self.timeLabel.frame.size.width;
[super layoutSubviews];
}
UITableView datasource methods :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell * cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:#"customCellId"];
// Set all label's text and image to ImageView
...
// Update layout
[cell setNeedsLayout];
[cell layoutIfNeeded];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
customCell * cell = (customCell *)[self tableView:tableView cellForRowAtIndexPath:indexPath];
NSString * userName = cell.userLabel.text;
NSString * chatText = cell.chatMessage.text;
// Get bounding rect of userName label
CGRect userNameFrame = [userName boundingRectWithSize:CGSizeMake(maxLabelWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:cell.userLabel.font} context:nil];
// Get bounding rect of chatMessage label
CGRect chatTextFrame = [chatText boundingRectWithSize:CGSizeMake(maxLabelWidth, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:cell.chatMessage.font} context:nil];
// Calculate cell height from its contents
height = userNameFrame.size.height + chatTextFrame.size.height + PADDING_ABOVE_TOP_LABEL + DISTANCE_BETWEEN_TWO_LABELS + PADDING_BELOW_BOTTOM_LABEL;
return height;
You can determine the cell height dynamically so that the text appears on one line. I've given CGSize(320,568) as bounds. But you can change the size as you see fit
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *chatText = [[chatData objectAtIndex:row] objectForKey:TEXT];
CGRect frame = [chatText boundingRectWithSize:CGSizeMake(320,568) options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:18.0f]} context:nil];
return frame.height; //returns cell's height after calculating the area that text needs
}
You are setting the frame of the text and calling sizeToFit:
CGSize size = [cell.textString.text sizeWithFont:cell.textString.font constrainedToSize:CGSizeMake(SET_WIDTH, MAXFLOAT) lineBreakMode:NSLineBreakByCharWrapping];
cell.textString.frame = ...;
[cell.textString sizeToFit];
This will not be working with autolayout. You need to remove setting the frame and sizeToFit completely, same goes for all other frame being set directly. If things don't work after that, it would mean some constraints are not correct. But mixing approaches always breaks layout.
For UILabels, make sure to also set preferredMaxLayoutWidth to label's width, otherwise text may not wrap correctly:
- (void)layoutSubviews
{
[super layoutSubviews];
self.label.preferredMaxLayoutWidth = self.label.frame.size.width;
[super layoutSubviews];
}
Also, your height calculating method should not just do same thing as cellForRowAtIndexPath:, if you want to use the same code, just call that other method to get a cell.

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

Resources