I have used UITableView to display items from database and I have created custom UITableViewCell which has a few labels. My largest label is name Description.
Each cell can have different height but I can't figure out how to set dynamic cell height.
All I get is three dots at the end of the label and height for cell is always about 50.
How to make cell height based on label inside it?
#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 320.0f
#define CELL_CONTENT_MARGIN 10.0f
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text = _orderProperty.Description;
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE]
constrainedToSize:constraint
lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height, 44.0f);
return height + (CELL_CONTENT_MARGIN * 2);
}
UPDATE
static NSString *CellIdentifier = #"orderDetailCell";
OrderDetailCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
[tableView registerNib:[UINib nibWithNibName:#"OrderDetailCustomCell" bundle:nil] forCellReuseIdentifier:CellIdentifier];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
}
OrderProperty* item = [_list objectAtIndex:indexPath.row];
cell.Title.text = item.Title;
NSString* _description = item.Description;
cell.Description.text = _description;
You can try something like this
- (CGFloat) tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
int rowHeight =0.0f;
NSString *stringToSize=[NSString stringWithFormat:#"%#",longStringValue];
CGSize size = [stringToSize
sizeWithFont:[UIFont systemFontOfSize:15.0f]
constrainedToSize:CGSizeMake(300, 6000)
lineBreakMode:NSLineBreakByWordWrapping];
rowHeight = size.height+10;
return rowHeight;
}
you may get the longStringValue from the array that you are using as a dataSource for your table
You can use following category on NSString, which use NSTextContainer and NSTextContainer to calculate the exact size of your text.
NSString+Calculation.m
And your final code will be like this:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *text = _orderProperty.Description;
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text usedSizeForMaxWidth:constraint.width
withFont:[UIFont systemFontOfSize:FONT_SIZE]];
CGFloat height = MAX(size.height, 44.0f);
return height + (CELL_CONTENT_MARGIN * 2);
}
sizeWithFont is now deprecated, please use the method below to set the height of the sell according the the text within the label.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
OrderProperty* item = [_list objectAtIndex:indexPath.row];
NSString *text = item.Description;
NSDictionary *stringAttributes = [NSDictionary dictionaryWithObject:[UIFont fontWithName:#"Helvetica" size:13] forKey:NSFontAttributeName];
CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize expectedLabelSize = [content boundingRectWithSize: constraint options:NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin attributes:stringAttributes context:nil].size;
return expectedLabelSize.height+CELL_CONTENT_MARGIN * 2);
}
Obviously you will need to adjust the string attributes to whatever you are using. These are simply for calculating the required height of the cell.
Related
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];
This question already has answers here:
Change the label width dynamically inside a UITableViewCell
(3 answers)
Closed 9 years ago.
I am trying to set the label width dynamically based on the content of the other label on the same line.
I am implementing the logic inside the "cellForRowAtIndexPath"
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"rowNumber:%d", indexPath.row);
EntityTableViewCell *cell = nil;
static NSString *CellIdentifier = #"Cell";
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.companyNameLabel.text = [group1 objectAtIndex:indexPath.row];
cell.companyCROfficeAddrLabel.text = [group2 objectAtIndex:indexPath.row];
cell.companyBusinessAddrLabel.text = [group3 objectAtIndex:indexPath.row];
cell.timestamp.text = [Utils getDateTimeString:[group4 objectAtIndex:indexPath.row]];
[cell.companyLogoImageView setImageWithURL:[NSURL URLWithString:[myArray objectAtIndex:indexPath.row] ]
placeholderImage:[UIImage imageNamed: #"profile-image-placeholder"]
options:indexPath.row == 0 ? SDWebImageRefreshCached : 0];
//logics to dynamically change the label width to maximum utilize the realstate
CGFloat timeStampWidth = [cell.timestamp.text sizeWithFont:cell.timestamp.font].width;
CGFloat ksCompanyNameLableMaxWidth = 235;
NSLog(#"timeStampWidth:%f", timeStampWidth);
CGSize companyNameLableSize = CGSizeMake((ksCompanyNameLableMaxWidth - timeStampWidth), cell.companyNameLabel.frame.size.height);
CGRect newFrame = cell.companyNameLabel.frame;
newFrame.size = companyNameLableSize;
cell.companyNameLabel.frame = newFrame;
NSLog(#"companyLableWidth:%f", newFrame.size.width);
return cell;
}
There are multiple problems with this code.
As the table is initialised, although this piece of code is called for every cell. The width of the label is still set as the size in the story board. On the other side, if I scroll down, the label is displayed correctly as designed in the code.
Because I also have a tabView controller within my app, whenever I switch between the tabs, the dynamically populated label width is getting updated with the default label width set in the storyboard again.
Could someone please tell me what I did wrong and suggest some solution?
Thanks
try this code
#define FONT_SIZE 14.0f
#define CELL_CONTENT_MARGIN 8.0f
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
NSString *text = [BugComments_text objectAtIndex:indexPath.row];
CGSize constraint = CGSizeMake(tableView.frame.size.width - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
CGFloat height = MAX(size.height+40, 60.0f);
return height + (CELL_CONTENT_MARGIN * 2);
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *text = [arrayofdata objectAtIndex:indexPath.row];
CGSize constraint = CGSizeMake(tableView.frame.size.width - (CELL_CONTENT_MARGIN * 2), 20000.0f);
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:NSLineBreakByWordWrapping];
[cell.Content_Text setText:text];
cell.Content_Text setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN+cell.Content_Email.frame.origin.y+cell.Content_Email.frame.size.height, tableView.frame.size.width - (CELL_CONTENT_MARGIN * 2), MAX(size.height,20.0f))];
}
Try this in your cellForRowAtIndexPath for dynamically setting the company label text,
CGSize textSize = {
200.0, // limit width
20000.0 // and height of text area
};
CGSize contentSize = [yourText sizeWithFont:[UIFont systemFontOfSize:17.0] constrainedToSize:textSize lineBreakMode:NSLineBreakByWordWrapping];
CGFloat contentHeight = contentSize.height < 36? 36: contentSize.height; // lower bound for height
CGRect companyLabelFrame = [cell.companyNameLabel frame];
companyLabelFrame.size.height = contentHeight;
[cell.companyNameLabel setFrame:companyLabelFrame];
cell.companyNameLabel setText:yourText];
I finally solve the problem by clearly specifying it again and get the answer from #rdelmar
please look the link Here
a boy of StackOverflow had given such help to set the height of the cells automatically based on the content of the label ...
I have implemented his method but when I scroll on tavleview, all the text in each cell overlaps and do not read anything ... Can you tell me what 's wrong with this code?
I had to change CGSize because I'm working on some code ios7 was deprecated for example:
CGSize size = [comment sizeWithFont: [UIFont systemFontOfSize: 14] constrainedToSize: lineBreakMode constraint: UILineBreakModeWordWrap];
Can you help me please?
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
PFObject *object = [self objectAtIndexPath:indexPath];
//Here you are getting the comment again. This is necessary to determine how tall you need
//the cell to be
NSString *comment = [object objectForKey:(#"Testo")];
// 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(250 - (10 * 2), 10000.0f);
// Again, determining the size that we will need for the label, because it will drive
// the height of the cell
UIFont *FONT = [UIFont systemFontOfSize:11];
CGSize size = [comment boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:FONT }context:nil].size;
// 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);
}
// Override to customize the look of a cell representing an object. The default is to display
// a UITableViewCellStyleDefault style cell with the label being the first key in the object.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSString *text = [object objectForKey:#"Testo"];
CGSize constraint = CGSizeMake(250 - (10 * 2), 10000.0f);
// This is determining the size that you will need for the label based on the comment
// length and the contraint size
UIFont *FONT = [UIFont systemFontOfSize:11];
CGSize size = [text boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:FONT }context:nil].size;
// 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 = NSLineBreakByWordWrapping;
label.text = text;
label.font = [UIFont systemFontOfSize:11];
// adding the label view to the cell that you have created
[cell.contentView addSubview:label];
// Configure the cell
return cell;
}
Solved
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
NSString *comment = [[self.objects objectAtIndex:[indexPath row]] objectForKey:#"Testo"];
CGFloat whidt = 260;
UIFont *FONT = [UIFont systemFontOfSize:15];
NSAttributedString *attributedText =[[NSAttributedString alloc] initWithString:comment attributes:# { NSFontAttributeName: FONT }];
CGRect rect = [attributedText boundingRectWithSize:(CGSize){whidt, MAXFLOAT}
options:NSStringDrawingUsesLineFragmentOrigin
context:nil];
CGSize size = rect.size;
return size.height +130;
}
- (FFCustomCellTimeline *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
FFCustomCellTimeline *cell = (FFCustomCellTimeline * )[self.tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (!cell) {
cell = [[FFCustomCellTimeline alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
}
NSString *text = [object objectForKey:#"Testo"];
CGSize constraint = CGSizeMake(260 , 20000.0f);
UIFont *FONT = [UIFont systemFontOfSize:15];
CGSize size = [text boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:FONT }context:nil].size;
return cell;
}
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.
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;
}