Probleme with height UITableViewCell - ios

This is my story:
I have a problem with the size of my IUTableViewCell. When I add several cell, the cell auto resizing.
any answer will be appreciated :)
That my code to resize:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPathInCellTable:(NSIndexPath *)indexPath {
CustomCell *cell = (CustomCell*) [self tableView:tableView
cellForRowAtIndexPath:indexPath];
CGSize size;
// SIZE HEIGHT TEXT
size = [cell.color.text sizeWithAttributes:
#{NSFontAttributeName:
[UIFont systemFontOfSize:12.0f]}];
// SIZE HEIGHT FOR CELL
CGRect frame = [cell frame];
frame.size.height += size.height;
[cell setFrame:frame];
// SIZE HEIGHT IMG
CGRect frame = [cell.img frame];
frame.size.height = 69;
frame.size.width = 69;
[cell.img setFrame:frame];
if (indexPath.row == 0) [self setHeightTableView:0];
_tableHeightConstraint.constant += cell.frame.size.height;
return cell.frame.size.height;
}
There some screenshot :
the first time i add a cell everything is fine
the same for the second cell everything is fine
And there the problem comes

You call CustomCell
*cell = (CustomCell*) [self tableView:tableView
cellForRowAtIndexPath:indexPath];
to get the a cell, which is wrong, because there is no cell created yet (so its nil). tableView:heightForCell:atIndexPath: get called before the cell was created. The best solution would be to have a module abject to save the height needed for your cell or make some similar calculations

Use a prototype cell to get the sizing instead of using tableView:cellForRowAtIndexPath:
http://www.samrayner.com/posts/dynamic-tableview-cells/

Related

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

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

Dynamic height reusable UITableViewCell

This question has been asked 100 times on SO, but I'm not able to solve my problem.
I've got two customizable cells. Both can have dynamic heights. My tableView:heightForRowAtIndexPath: returns the proper height for each cell, but when cells are reused, the separator line between cells isn't in the right spot 100% of the time. I can't use the hack of adding my own line in my cells because sometimes the overlap is so bad you can't click on the right cell.
What do I need to do to make sure it uses the proper height?
Here is an example of the separator line being in the wrong spots (supposed to be right above the title):
Here is how I set my heights:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
InspectionItem *item = [items objectAtIndex:indexPath.row];
int t = [item.rating.ratingType ratingTypeK];
if (t == RatingTypeTextfield){
CGFloat height = [OQCTextFieldCell heightOfCellWithTitle:item.name
subtext:item.descriptionText
text:item.comment
andScreenWidth:self.view.frame.size.width];
return height;
}
else {
CGFloat height = [OQCButtonCell heightOfCellWithTitle:item.name
subtext:item.descriptionText
andScreenWidth:self.view.frame.size.width];
return height;
}
}
Again, these class methods return the proper heights.
Here is how I set my cells up (short version):
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
InspectionItem *item = [items objectAtIndex:indexPath.row];
int t = [item.rating.ratingType ratingTypeK];
if (t == RatingTypeTextfield){
static NSString *CellIdentifier = #"TextFieldCell";
OQCTextFieldCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.titleLabel.text = item.name;
...
return cell;
}
else {
static NSString *CellIdentifier = #"ButtonCell";
OQCButtonCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.titleLabel.text = item.name;
...
return cell;
}
}
Here is how I'm registering my cells:
UINib *buttonNib = [UINib nibWithNibName:#"OQCButtonCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:buttonNib forCellReuseIdentifier:#"ButtonCell"];
UINib *textFieldNib = [UINib nibWithNibName:#"OQCTextFieldCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:textFieldNib forCellReuseIdentifier:#"TextFieldCell"];
UINib *flagNib = [UINib nibWithNibName:#"OQCFlagCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:flagNib forCellReuseIdentifier:#"FlagCell"];
My cells only overwrite layoutSubviews and they do call super first thing.
I need the solution to be good for iOS 5.2+.
Update
Here is my code for layoutSubviews. I do believe that my custom method heightOfCellWithTitle:subtext:text: returns the right height since it matches what the layoutSubview height variable is at the end of this method.
- (void)layoutSubviews
{
[super layoutSubviews];
CGFloat height = 0;
// Title + Header background view
NSString *title = titleLabel.text;
CGRect frame = self.titleLabel.frame;
CGSize size = [title sizeWithFont:titleLabel.font
constrainedToSize:CGSizeMake(frame.size.width, 9999)
lineBreakMode:titleLabel.lineBreakMode];
size.width = frame.size.width; // don't let it shrink
titleLabel.numberOfLines = size.height / titleLabel.font.lineHeight;
frame.size = size;
self.titleLabel.frame = frame;
frame = self.headerBackgroundView.frame;
frame.size.height = size.height + 8;
self.headerBackgroundView.frame = frame;
// single line of text should be 30
height += frame.size.height;
CGRect subContentFrame = subContentView.frame;
subContentFrame.origin.y = height;
CGFloat subHeight = 0;
// Label
title = subtextLabel.text;
if ([title length] > 0){
subHeight += 5; // top margin
size = [title sizeWithFont:subtextLabel.font
constrainedToSize:CGSizeMake(subtextLabel.frame.size.width, 9999) lineBreakMode:subtextLabel.lineBreakMode];
size.width = self.contentView.frame.size.width - 52; // don't let it shrink
subtextLabel.numberOfLines = size.height / subtextLabel.font.lineHeight;
frame = self.subtextLabel.frame;
frame.size = size;
frame.origin.y = subHeight;
self.subtextLabel.frame = frame;
// subtext height + bottom margin
subHeight += size.height + 5;
}
else {
subHeight += 25;
}
// Button
frame = button.frame;
frame.origin.y = subHeight;
button.frame = frame;
subHeight += frame.size.height + 25;
subContentFrame.size.height = subHeight;
subContentView.frame = subContentFrame;
// reposition detailIndicator
frame = self.detailIndicator.frame;
frame.origin.x = subContentView.frame.size.width - 37;
self.detailIndicator.frame = frame;
height += subHeight;
// Drawer
frame = CGRectMake(0, 0, self.frame.size.width, height);
[self.drawerView setFrame:frame];
self.backgroundView = self.drawerView;
}
Also, quick note about the numbers I've been checking.
I have a log on layoutSubviews and tableView:heightForRowAtIndexPath: which give me correct heights (I'm basing that off of layoutSubviews since it is recalculating the height for the entire cell). And then I have a log for tableView:cellForRowAtIndexPath: which at the end just before I return the cell I print out the cell's height, and it is an old height of a reused view, which I kind of expect. I would assume that after the cell is returned that iOS will recalculate what the position of the cell should be based on tableView:heightForRowAtIndexPath: and reposition the views with layoutSubviews.
so if you layout the cells dynamically in the cell class and overwrite layoutSubviews this should be enough in heightForRowAtIndexPath:
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
float height = cell.frame.size.height;
return height;
remember that you have to "reset" all uiviews in your cell to the start values. otherwise the the cell will use the current values, i.e. if you have a label at y=10 and set it programmatically to y=20, next time the cell is used the cell still have y=20.
Have you tried calling
[cell setNeedsLayout];
[cell layoutIfNeeded];
before returning it?

dequeueReusableCellWithIdentifier with cells of different size

STEP 1 - this is working fine
I have UITableView that loads custom UITableViewCells
STEP 2 - this is kinda works
I change the UITableViewCell height so that all the data contained in the cell within a UITextView is visible
I manage to get the UItextView data and resize it by using the following code:
UITextView *dummy = [[UITextView alloc] init];
dummy.font = [UIFont systemFontOfSize:14];
dummy.text = cell.textView.text;
CGSize newSize = [dummy sizeThatFits:CGSizeMake(270.0f, 500.0f)];
//get the textView frame and change it's size
CGRect newFrame = cell.textView.frame;
newFrame.size = CGSizeMake(270.0f, fmaxf(newSize.height, 60));
cell.textView.frame = newFrame;
//resize the cell view I add +95 because my cell has borders and other stuff...
CGRect cellFrame = CGRectMake(0, 0, 320, newFrame.size.height+95);
cell.cellView.frame = cellFrame;
I then manage to set the UITableViewCell height using the delegate function heightForRowAtIndexPath:
Now when I run the code and scroll up and down the table cells the behavious isn't always as expected... i.e the cell size isn't always the right size, but if I scroll up and down it sometimes loads up the right size again.
I am thinking that perhaps the dequeueReusableCellWithIdentifier is the issue
cellIdentifier = #"tableCell";
ctTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
Since I am recycling cells of different size with the same identifier...
Can anybody give me some guidelines on how best to solve this issue?
Thanks!!!
I would start by adding UITextView dynamically inside cellForRowAtIndexPath method. assumptions(data array contains the content to be displayed inside cell)
// Defines
#define CELL_TEXTVIEW_WIDTH = 320
#define CELL_TEXTVIEW_HEIGHT = 9999
#define PADDING = 5
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"tableCell";
ctTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];
if(cell == nil){
cell = [[tableView alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *_data = [data objectAtIndex:indexPath.row];
CGSize _data_contentsize = [_data sizeWithFont:[UIFont systemFontOfSize:14] constrainedToSize:CGSizeMake(CELL_TEXTVIEW_WIDTH, CELL_TEXTVIEW_HEIGHT) lineBreakMode:NSLineBreakModeWordWrap];
UITextView *dummy=[[UITextView alloc] initWithFrame:CGRectMake(5, 5, 290, _data_contentsize +(PADDING * 2))];
// add Font and text color for your textview here
[cell.contentView addSubview:dummy];
return cell;
}
After this calculate the height of the cell under heightForRowAtIndexPath method.
have you implemented following method ?
(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
https://developer.apple.com/library/ios/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath:
you should set height for each row , if they are different from each other

UILabels not resizing in UITableView

I have a UITableView that uses prototype cells. The cells have a custom class called dataCell. The custom cells also have three UILabels:idLabel, contLabel, and expLabel. The cells properly resize based on the amount of text in expLabel; however, I cannot get the label itself to resize. Some labels resize when I scroll down; however, they also revert to showing only two lines and omitting text when I scroll back up. Here is my code
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
dataCell *cell = (dataCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// the rest of your configure cell
// First Cell Label
[cell.idLabel setText:[idData objectAtIndex:indexPath.row]];
cell.idLabel.numberOfLines = 0;
// Second Cell Label
[cell.contLabel setText:[conData objectAtIndex:indexPath.row]];
cell.contLabel.numberOfLines = 0;
// Third Cell Label
[cell.expLabel setText:[expData objectAtIndex:indexPath.row]];
cell.expLabel.numberOfLines=0;
CGSize expectedLabelSize = [cell.expLabel.text sizeWithFont:cell.expLabel.font constrainedToSize:CGSizeMake(220, FLT_MAX) lineBreakMode:cell.expLabel.lineBreakMode];
cell.expLabel.frame=CGRectMake(cell.expLabel.frame.origin.x, cell.expLabel.frame.origin.y, expectedLabelSize.width, expectedLabelSize.height);
return cell;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath {
dataCell *cell = (dataCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
CGSize maximumLabelSize = CGSizeMake(220, FLT_MAX);
[cell.expLabel setText:[expData objectAtIndex:indexPath.row]];
CGSize expectedLabelSize = [cell.expLabel.text sizeWithFont:cell.expLabel.font constrainedToSize:maximumLabelSize lineBreakMode:cell.expLabel.lineBreakMode];
if (expectedLabelSize.height<43) {
expectedLabelSize.height=43;
}
return expectedLabelSize.height; }
Any help would be much appreciated
If you are using a storyboard and a UITableViewCell then you can just change the auto resizing mask, but if you are doing it programmatically then you will have to set the calculate the text width and height and reset the frame of the labels,
UILabel* label = [[UILabel alloc] init];
UIFont* font = label.font;
CGSize maxContentSizeForText = CGSizeMake(maxTextWidth, maxTextHeight);
CGSize stringTextSize = [string sizeWithFont:font constrainedToSize:maxContentSizeForText lineBreakMode:NSLineBreakByWordWrapping];
[label setFrame:CGRectMake(xPosition, yPosition, stringTextSize.width, stringTextSize.height);
[label setNumberOfLines:1000];
your label is probably a property from a xib file or storyboard, and the number of lines is just saying that you want the label to get really really big, since we can't say "infinite" i just generally use 1000 indicating 1000 lines of text maximum

Cells Labels Not Resizing Until Table Scrolling

I'm using this code to resize the labels that maintains the titles of my cells. The problem is that the cells labels are not resizing until I scroll the table. Cells need to disappear to resize their labels correctly. What can I do to get all the cells labels well resized without having to scroll previously?
Thanks for reading.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
ExampleTableViewCell *cell = (ExampleTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"ExampleTableViewCell"];
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"ExampleTableViewCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
cell.title.text = [self.test objectAtIndex:[indexPath row]];
//Calculates the expected size based on the font and linebreak mode of the label.
CGSize maximumLabelSize = CGSizeMake(200, [UIScreen mainScreen].bounds.size.width);
CGSize expectedLabelSize = [cell.title.text sizeWithFont:cell.title.font constrainedToSize:maximumLabelSize lineBreakMode:cell.title.lineBreakMode];
// Adjusts the label the the new height.
CGRect newFrame = cell.title.frame;
newFrame.size.height = expectedLabelSize.height;
cell.title.frame = newFrame;
return cell;
}
Try to write the same code in
willDisplayCell method of UItableViewController
Another approach is .... in your ExampleTableViewCell class implement
- (void)layoutSubviews{
}
set your title's frame in above function. It should work
you must implement the method heightForRowAtIndexPath and return the height of cell then your problem solved :-)
I found Matt Long's solution really helpful (http://www.cimgf.com/2009/09/23/uitableviewcell-dynamic-height/).

Resources