I am using a custom UITableViewCell which has some labels, buttons and image views to be displayed. There is one label in the cell whose text is a NSString object and the length of string could be variable. Due to this, I cannot set a constant height to the cell in the UITableView's heightForCellAtIndex method. The cell's height depends on the label's height which can be determined using the NSString's sizeWithFont method. I tried using it, but it looks like I'm going wrong somewhere. How can it be fixed?
Here is the code used for initializing the cell.
if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier])
{
self.selectionStyle = UITableViewCellSelectionStyleNone;
UIImage *image = [UIImage imageNamed:#"dot.png"];
imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(45.0,10.0,10,10);
headingTxt = [[UILabel alloc] initWithFrame: CGRectMake(60.0,0.0,150.0,post_hdg_ht)];
[headingTxt setContentMode: UIViewContentModeCenter];
headingTxt.text = postData.user_f_name;
headingTxt.font = [UIFont boldSystemFontOfSize:13];
headingTxt.textAlignment = UITextAlignmentLeft;
headingTxt.textColor = [UIColor blackColor];
dateTxt = [[UILabel alloc] initWithFrame:CGRectMake(55.0,23.0,150.0,post_date_ht)];
dateTxt.text = postData.created_dtm;
dateTxt.font = [UIFont italicSystemFontOfSize:11];
dateTxt.textAlignment = UITextAlignmentLeft;
dateTxt.textColor = [UIColor grayColor];
NSString * text1 = postData.post_body;
NSLog(#"text length = %d",[text1 length]);
CGRect bounds = [UIScreen mainScreen].bounds;
CGFloat tableViewWidth;
CGFloat width = 0;
tableViewWidth = bounds.size.width/2;
width = tableViewWidth - 40; //fudge factor
//CGSize textSize = {width, 20000.0f}; //width and height of text area
CGSize textSize = {245.0, 20000.0f}; //width and height of text area
CGSize size1 = [text1 sizeWithFont:[UIFont systemFontOfSize:11.0f]
constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];
CGFloat ht = MAX(size1.height, 28);
textView = [[UILabel alloc] initWithFrame:CGRectMake(55.0,42.0,245.0,ht)];
textView.text = postData.post_body;
textView.font = [UIFont systemFontOfSize:11];
textView.textAlignment = UITextAlignmentLeft;
textView.textColor = [UIColor blackColor];
textView.lineBreakMode = UILineBreakModeWordWrap;
textView.numberOfLines = 3;
textView.autoresizesSubviews = YES;
[self.contentView addSubview:imageView];
[self.contentView addSubview:textView];
[self.contentView addSubview:webView];
[self.contentView addSubview:dateTxt];
[self.contentView addSubview:headingTxt];
[self.contentView sizeToFit];
[imageView release];
[textView release];
[webView release];
[dateTxt release];
[headingTxt release];
}
This is the label whose height and width are going wrong:
textView = [[UILabel alloc] initWithFrame:CGRectMake(55.0,42.0,245.0,ht)];
Your UITableViewDelegate should implement tableView:heightForRowAtIndexPath:
Objective-C
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [indexPath row] * 20;
}
Swift 5
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return indexPath.row * 20
}
You will probably want to use NSString's sizeWithFont:constrainedToSize:lineBreakMode: method to calculate your row height rather than just performing some silly math on the indexPath :)
If all your rows are the same height, just set the rowHeight property of the UITableView rather than implementing the heightForRowAtIndexPath. Apple Docs:
There are performance implications to using tableView:heightForRowAtIndexPath: instead of rowHeight. Every time a table view is displayed, it calls tableView:heightForRowAtIndexPath: on the delegate for each of its rows, which can result in a significant performance problem with table views having a large number of rows (approximately 1000 or more).
in a custom UITableViewCell -controller add this
-(void)layoutSubviews {
CGRect newCellSubViewsFrame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
CGRect newCellViewFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height);
self.contentView.frame = self.contentView.bounds = self.backgroundView.frame = self.accessoryView.frame = newCellSubViewsFrame;
self.frame = newCellViewFrame;
[super layoutSubviews];
}
In the UITableView -controller add this
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return [indexPath row] * 1.5; // your dynamic height...
}
#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 300.0f
#define CELL_CONTENT_MARGIN 10.0f
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
/// Here you can set also height according to your section and row
if(indexPath.section==0 && indexPath.row==0)
{
text=#"pass here your dynamic data";
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = MAX(size.height, 44.0f);
return height + (CELL_CONTENT_MARGIN * 2);
}
else
{
return 44;
}
}
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
UILabel *label = nil;
cell = [tv dequeueReusableCellWithIdentifier:#"Cell"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:#"Cell"];
}
********Here you can set also height according to your section and row*********
if(indexPath.section==0 && indexPath.row==0)
{
label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setLineBreakMode:UILineBreakModeWordWrap];
[label setMinimumFontSize:FONT_SIZE];
[label setNumberOfLines:0];
label.backgroundColor=[UIColor clearColor];
[label setFont:[UIFont systemFontOfSize:FONT_SIZE]];
[label setTag:1];
// NSString *text1 =[NSString stringWithFormat:#"%#",text];
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
if (!label)
label = (UILabel*)[cell viewWithTag:1];
label.text=[NSString stringWithFormat:#"%#",text];
[label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];
[cell.contentView addSubview:label];
}
return cell;
}
I saw a lot of solutions but all was wrong or uncomplet.
You can solve all problems with 5 lines in viewDidLoad and autolayout.
This for objetive C:
_tableView.delegate = self;
_tableView.dataSource = self;
self.tableView.estimatedRowHeight = 80;//the estimatedRowHeight but if is more this autoincremented with autolayout
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self.tableView setNeedsLayout];
[self.tableView layoutIfNeeded];
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0) ;
For swift 2.0:
self.tableView.estimatedRowHeight = 80
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.setNeedsLayout()
self.tableView.layoutIfNeeded()
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0)
Now create your cell with xib or into tableview in your Storyboard
With this you no need implement nothing more or override. (Don forget number os lines 0) and the bottom label (constrain) downgrade "Content Hugging Priority -- Vertical to 250"
You can donwload the code in the next url:
https://github.com/jposes22/exampleTableCellCustomHeight
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
CGSize constraintSize = {245.0, 20000}
CGSize neededSize = [ yourText sizeWithFont:[UIfont systemFontOfSize:14.0f] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeCharacterWrap]
if ( neededSize.height <= 18)
return 45
else return neededSize.height + 45
//18 is the size of your text with the requested font (systemFontOfSize 14). if you change fonts you have a different number to use
// 45 is what is required to have a nice cell as the neededSize.height is the "text"'s height only
//not the cell.
}
To set automatic dimension for row height & estimated row height, ensure following steps to make, auto dimension effective for cell/row height layout.
Assign and implement tableview dataSource and delegate
Assign UITableViewAutomaticDimension to rowHeight & estimatedRowHeight
Implement delegate/dataSource methods (i.e. heightForRowAt and return a value UITableViewAutomaticDimension to it)
-
Objective C:
// in ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
#property IBOutlet UITableView * table;
#end
// in ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.table.dataSource = self;
self.table.delegate = self;
self.table.rowHeight = UITableViewAutomaticDimension;
self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Swift:
#IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Don't forget to set dataSource and delegate for table
table.dataSource = self
table.delegate = self
// Set automatic dimensions for row height
table.rowHeight = UITableViewAutomaticDimension
table.estimatedRowHeight = UITableViewAutomaticDimension
}
// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
For label instance in UITableviewCell
Set number of lines = 0 (& line break mode = truncate tail)
Set all constraints (top, bottom, right left) with respect to its superview/ cell container.
Optional: Set minimum height for label, if you want minimum vertical area covered by label, even if there is no data.
Note: If you've more than one labels (UIElements) with dynamic length, which should be adjusted according to its content size: Adjust 'Content Hugging and Compression Resistance Priority` for labels which you want to expand/compress with higher priority.
Here in this example I set low hugging and high compression resistance priority, that leads to set more priority/importance for contents of second (yellow) label.
Thanks to all the posts on this topic, there are some really helpful ways to adjust the rowHeight of a UITableViewCell.
Here is a compilation of some of the concepts from everyone else that really helps when building for the iPhone and iPad. You can also access different sections and adjust them according to the varying sizes of views.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
int cellHeight = 0;
if ([indexPath section] == 0)
{
cellHeight = 16;
settingsTable.rowHeight = cellHeight;
}
else if ([indexPath section] == 1)
{
cellHeight = 20;
settingsTable.rowHeight = cellHeight;
}
return cellHeight;
}
else
{
int cellHeight = 0;
if ([indexPath section] == 0)
{
cellHeight = 24;
settingsTable.rowHeight = cellHeight;
}
else if ([indexPath section] == 1)
{
cellHeight = 40;
settingsTable.rowHeight = cellHeight;
}
return cellHeight;
}
return 0;
}
To have the dynamic cell height as the text of Label increases, you first need to calculate height,that the text gonna use in -heightForRowAtIndexPath delegate method and return it with the added heights of other lables,images (max height of text+height of other static componenets) and use same height in cell creation.
#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 300.0f
#define CELL_CONTENT_MARGIN 10.0f
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (indexPath.row == 2) { // the cell you want to be dynamic
NSString *text = dynamic text for your label;
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = MAX(size.height, 44.0f);
return height + (CELL_CONTENT_MARGIN * 2);
}
else {
return 44; // return normal cell height
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UILabel *label;
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] ;
}
label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, 280, 34)];
[label setNumberOfLines:2];
label.backgroundColor = [UIColor clearColor];
[label setFont:[UIFont systemFontOfSize:FONT_SIZE]];
label.adjustsFontSizeToFitWidth = NO;
[[cell contentView] addSubview:label];
NSString *text = dynamic text fro your label;
[label setText:text];
if (indexPath.row == 2) {// the cell which needs to be dynamic
[label setNumberOfLines:0];
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
[label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];
}
return cell;
}
Related
I have to solve some problems in existing project (Objective-C, Xcode 7.3, iOS).
Here I have a Table View in which I need to have some resizable cells to fit the content. The cells include Labels. The project uses UITableViewAutomaticDimension but it doesn't seem to work properly. The text in the cell goes beyond the right border.
So now i've checked some points:
The "Lines" property of the cell in Attributes Inspector is set to 0.
I have 4 constraints for the Label (pic related).
The heightForRowAtIndexPath method contains only return UITableViewAutomaticDimension;.
Here is the code, where UITableViewAutomaticDimension is used:
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.estimatedRowHeight = 50.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;
}
Constraints screenshot <======
Try this
- (CGFloat)tableView:(UITableView *)_tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 186, 0)]; //max width that is allowed for label
lbl.numberOfLines = 0;
lbl.lineBreakMode = NSLineBreakByWordWrapping;
int GAP = 3;
float height = 0;
float fontSize = 14;
NSString *cellText = yourtext;
lbl.font= [ UIFont fontWithName:FONT_NAME_Ubuntu size: fontSize];
bl.text = cellText;
[lbl sizeToFit];
height += lbl.frame.size.height;
height += GAP;
return height;
}
Or try below one
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
/*
for dynamic cell heigh according to the description display in cell
*/
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;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
You need set in IB or in code
[yourLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis: UILayoutConstraintAxisVertical];
[yourLabel setContentHuggingPriority:UILayoutPriorityRequired forAxis: UILayoutConstraintAxisVertical];
And after set the text call this
[cell setNeedsDisplay];
[cell layoutIfNeeded];
Hope this help. I took this from Self Sizing example from Apple
I have a long label that is my first label, and I want to fit it in my cell. This is what I have but it isn't working.
I have a custom UITabelviewCell with a few labels in it.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
switch (indexPath.row) {
case 0:{
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [diningHallTimes[indexPath.row][#"description"] sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height, 44.0f);
return height + (CELL_CONTENT_MARGIN * 2) + 40;
// return myStringSize.height;
break;
}
default:
return 40;
break;
}
}
Here is cell for row
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DiningInfoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [diningHallTimes[indexPath.row][#"description"] sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height, 44.0f);
CGFloat the = height + (CELL_CONTENT_MARGIN * 2);
cell.descriptionLabel.numberOfLines = 0;
[cell.descriptionLabel setFrame:CGRectMake(20, 0, 280, the)];
NSLog(#"%f", the);
cell.descriptionLabel.text = diningHallTimes[indexPath.row][#"description"];
cell.daysLabel.text = diningHallTimes[indexPath.row][#"days"];
cell.timeLabel.text = diningHallTimes[indexPath.row][#"time"];
return cell;
}
But then this is what my cell looks like
Not sure why this is happening, I am running iOS8, but I need it to work for both is and 7.
Thanks for the help in advance.
You need to calculate boundingRectWithSize: for label text. Also need to calculate number of lines required for updated content also. Try this below method to calculate new frame for label.
- (UILabel *) updateLabelFrame:(UILabel *)label {
CGRect lblRect = label.frame;
CGSize maxSize = CGSizeMake(label.frame.size.width, MAXFLOAT);
CGRect labelRect = [label.text boundingRectWithSize:maxSize options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:label.font} context:nil];
CGFloat labelHeight = labelRect.size.height;
// For below line 16 is default height (The height before content is set). Change this value
// as per your requirement
int lines = labelHeight / 16; // Here 16 is a fix height (default height) for label.
[label setNumberOfLines:lines];
lblRect.size.height = labelHeight;
[label setFrame:lblRect];
return label;
}
Edit:
You can place this method any where you want. Like some base class or in same view controller. Here I modified above method which will return label with dynamic frame.
For your case you need to place this method in view controller class. Then call this method in -cellForRowAtIndexPath after content is updated for label. See below code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
DiningInfoTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [diningHallTimes[indexPath.row][#"description"] sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height, 44.0f);
CGFloat the = height + (CELL_CONTENT_MARGIN * 2);
cell.descriptionLabel.numberOfLines = 0;
[cell.descriptionLabel setFrame:CGRectMake(20, 0, 280, the)];
NSLog(#"%f", the);
cell.descriptionLabel.text = diningHallTimes[indexPath.row][#"description"];
cell.daysLabel.text = diningHallTimes[indexPath.row][#"days"];
cell.timeLabel.text = diningHallTimes[indexPath.row][#"time"];
// Update descriptionLabel height.
cell.descriptionLabel = [self updateLabelFrame:cell.descriptionLabel];
return cell;
}
You have to set up Autolayout constraints for the label and create a prototype cell with the content. And then you have to return then you have to get the height of the cell.
For reference , you could see the following video
https://www.youtube.com/watch?v=6KImie4ZMwk
Try [yourLabel sizeToFit] or you may use [yourLabel sizeThatFit:CGFrame];
I found a lot of answer for this question but I don't anderstand how to manage my code.
When I scroll the tableView content, the cell disappear. I just have two texts in the cell question and answer.
I've tried to use an identifier (reusable) but the code doesn't change anything...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UILabel *textLabel = nil;
NSString* text = #"";
//static NSString *CellIdentifier = #"Cell";
NSString *CellIdentifier = [NSString stringWithFormat:#"%ld_%ld",(long)indexPath.section,(long)indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
int y = -20;
float titleFontSize = 14.0f;
if(indexPath.row == 0) {
y = 0;
titleFontSize = 16.0f;
}
if(cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
textLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[textLabel setLineBreakMode:NSLineBreakByWordWrapping];
[textLabel setMinimumFontSize:14.0f];
[textLabel setNumberOfLines:0];
[textLabel setFont:[UIFont systemFontOfSize:14.0f]];
[textLabel setTag:1];
[textLabel setTextColor:[UIColor colorWithRed:57/255.0 green:55/255.0 blue:64/255.0 alpha:1.0]];
// Titre
if(indexPath.row == 0) {
text = question;
[cell setBackgroundColor:[UIColor colorWithRed:220/255.0 green:224/255.0 blue:241/255.0 alpha:1.0]];//[UIColor colorWithRed:.945f green:.921f blue:.78f alpha:1]];
[textLabel setFont:[UIFont fontWithName:#"Helvetica-Bold" size:titleFontSize]];
}
// Contenu
else {
text = answer;
}
CGSize constraint = CGSizeMake(285, 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:titleFontSize] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
[textLabel setText:text];
[textLabel setFrame:CGRectMake(25, y, 275, MAX(size.height + 60, 44.0f))];
[textLabel setBackgroundColor:[UIColor clearColor]];
[cell addSubview:textLabel];
return cell;
}
UPDATE CALCULATING CELL SIZE
-(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
float titleFontSize = 14.0f;
float offSet = 0;
NSString *text = #"";
if(indexPath.row == 0) {
text = question;
titleFontSize = 16.f;
offSet = 10;
}
else
text = answer;
CGSize constraint = CGSizeMake(285, 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:titleFontSize] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height + 40, 44.0f);
return height + offSet;
}
I've had this problem in the past and it's always due to the cells height being incorrect... You've got quite a few instances where your two cells are not the same, so we are going to have to get a grip on that code.
int y
this value is also concerning me a little as it looks like it sets the textLabel frame origin.y to -20 ... if you want a different offset for Y in each cell but the rest of the cell is the same, that's fine, but in this case I think I'd suggest a different UITableViewCell subclass for the two types of cell... And change all the label properties etc inside that subclass..
So...
Make a UITableViewCell subclass for each type of cell, call them whatever you like... for example MYQuestionTableViewCell and MYAnswerTableViewCell
inside the cell MYQuestionTableViewCell .h file
#define TEXT_LABEL_WIDTH 285.0f
#define TEXT_LABEL_QUESTION_FONT_SIZE 16.0f
inside that cell MYQuestionTableViewCell .m file do
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.backgroundColor = [UIColor redColor];
self.clipsToBounds = YES; // just to make sure we're calculating the height correctly
// set up your textLabel etc. in here
self.textLabel.textColor = [UIColor whiteColor];
self.textLabel.font = [UIFont fontWithName:#"Helvetica-Bold" size: TEXT_LABEL_QUESTION_FONT_SIZE]];
}
return self;
}
-(void)layoutSubviews
{
[super layoutSubviews];
self.textLabel.frame = CGRectMake(0.0f, 0.0f, TEXT_LABEL_WIDTH, self.contentView.frame.size.height);
}
Now our textLabel will be whatever the height of the cell is... Now it's set in only one place, we know where the issue will be if it's not correct.
In your second MYAnswerTableViewCell subclass you'll need the other values set
.h
#define TEXT_LABEL_ANSWER_FONT_SIZE 14.0f
.m
same as the other cell but changing for it's property values
As you are also using different fonts in the two different cells... it might be easier to use a switch.. but I'll try to keep it similar to what you were doing before.. this sort of doubling up of code is the cause of the confusion, but sometimes it's unavoidable.. We'll just try to keep it as simple as we can.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat offSet = 0.0;
NSString *text = #"";
UIFont *fontUsed = nil;
if(indexPath.row == 0) {
fontUsed = [textLabel setFont:[UIFont fontWithName:#"Helvetica-Bold" size: TEXT_LABEL_QUESTION_FONT_SIZE]];
text = question;
offSet = 10.0f;
}
else
{
fontUsed =[UIFont systemFontOfSize:TEXT_LABEL_ANSWER_FONT_SIZE];
text = answer;
}
NSLog (#"TEXT: %#",text); // checking if the text is set...
CGSize constraint = CGSizeMake(TEXT_LABEL_WIDTH, HUGE_VALF); // personally I prefer HUGE_VALF for that
CGSize size = [text sizeWithFont:fontUsed constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height + 40.0f, 44.0f); // 40.0f for padding?
return height + offSet;
}
You shouldn't be adding labels to a cell unless you need to, they come with some provided... now your cellForRow can look like this
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *QuestionCellIdentifier = #"QuestionCell";
static NSString *AnswerCellIdentifier = #"AnswerCell";
if (indexPath.row == 0)
{
MYQuestionTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:QuestionCellIdentifier];
if (!cell)
cell = [[MYQuestionTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:QuestionCellIdentifier];
cell.textLabel.text = question;
return cell;
}
MYAnswerTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: AnswerCellIdentifier];
if (!cell)
cell = [[MYAnswerTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:AnswerCellIdentifier];
cell.textLabel.text = answer;
return cell;
}
You'll also need
#import "MYQuestionTableViewCell.h"
#import "MYAnswerTableViewCell.h"
at the top of your view controller
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);
}
I am trying to get the UITableView cells to fit the text. So far I have something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UILabel *label = nil;
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)
reuseIdentifier:#"business"];
NSString *comment = [[items_array objectAtIndex:[indexPath row]] objectForKey:(#"comment")];
cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
CGSize constraint = CGSizeMake(320 - (10 * 2), 20000.0f);
CGSize size = [comment sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];
label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:comment];
[label setFrame:CGRectMake(10, 10, 320 - (10 * 2), MAX(size.height, 44.0f))];
cell.textLabel.text = comment;
}
I also have this function
- (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);
}
But it isn't allocating the right amount of height to the cells of the UITableViews. I think I am making some mistakes with how/where I assign the label and the text of the cells.
Please help me understand how it should be.
Thanks!
does this get you closer?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"business"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault)reuseIdentifier:#"business"];
}
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];
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];
}
You need to set height of a cell using -tableView:heightForRowAtIndexPath.
With the new code posted
Here is how I did it (I used a prototype cell so things may be different for you).
I set the the autosizing of the cell to auto size the height of the label (this may already be set for the textLabel).
Then in -tableView:heightForRowAtIndexPath I did the following:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
CGSize size = CGSizeMake(WIDTH_OF_PROTOTYPE_LABEL, CGFLOAT_MAX);
size = [TEXT_AT_INDEX_PATH sizeWithFont:FONT_OF_PROTOTYPE_LABEL constrainedToSize:size lineBreakMode:UILineBreakModeWordWrap];
CGFloat height = size.height + (HEIGHT_OF_PROTOTYPE_CELL - HEIGHT_OF_PROTOTYPE_LABEL);
return MAX(height, HEIGHT_OF_PROTOTYPE_CELL);
}
Update 2
In looking at your code again, I see two possible problems. 1) You have the width of the textLabel wrong. 2) You should compute the do MAX as the last thing after you compute the final new height.