Dynamic height reusable UITableViewCell - ios

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?

Related

Xcode 6: Label in Table Cell won't expand / display longer text upon expansion / line up with cell

The Problem:
I've got a label in a table cell as follows:
EDIT: While the tableview does not use AutoLayout, the xib for the cell does. This is what it looks like:
Now, the "..." means the review (the text) is too long to be displayed. The user can then click on the cell, which would expand the cell and the label downwards, which would then show the rest of the text.
Here's the code for the heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (tableView == self.rateAndReviewView.ratingsTable) {
BOOL isSelected = [self.selectedIndexPaths containsObject:indexPath];
CGFloat maxHeight = MAXFLOAT;
CGFloat minHeight = 40.0f;
if (isSelected){
CGFloat constrainHeight = isSelected?maxHeight:minHeight;
CGFloat constrainWidth = tableView.frame.size.width - 20.0f;
//
SQLReview *review = [reviewsArray objectAtIndex:indexPath.row];
NSString *text = review.comment;
CGSize constrainSize = CGSizeMake(constrainWidth, constrainHeight);
CGSize labelSize = [text sizeWithFont:[UIFont systemFontOfSize:15.0f]
constrainedToSize:constrainSize
lineBreakMode:NSLineBreakByWordWrapping];
CGFloat labelHeight = labelSize.height;
return MAX(labelHeight+20, 100.0f);
} else {
minHeight = 100.0f;
return minHeight;
}
}
}
And this is the code for the cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (tableView == self.rateAndReviewView.ratingsTable) {
static NSString *CellIdentifier = #"Cell";
VenueReviewCell *cell = (VenueReviewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
cell = [[[NSBundle mainBundle] loadNibNamed:#"ReviewCell" owner:nil options:nil] objectAtIndex:0];
}
[cell.contentView.layer setBorderWidth:0.5f];
cell.contentView.backgroundColor = [UIColor whiteColor];
SQLReview *review = [reviewsArray objectAtIndex:indexPath.row];
cell.usernameLabel.text = (review.user_name == nil) ? #"" : review.user_name;
cell.datetimeLabel.text = (review.datetime == nil) ? #"" : [review.datetime substringToIndex:10];
cell.commentLabel.text = (review.comment == nil) ? #"" : review.comment;
cell.commentLabel2.text = (review.comment == nil) ? #"" : review.comment;
float overallScore = (review.overall == nil) ? 0.0f : [review.overall floatValue];
NSArray *overallImageViewArray = #[cell.overallStarImageView1, cell.overallStarImageView2, cell.overallStarImageView3, cell.overallStarImageView4, cell.overallStarImageView5];
if([selectedIndexPaths containsObject:indexPath]) {
cell.commentLabel.hidden = YES;
cell.commentLabel2.hidden = NO;
CGSize commentLabelComputeSize = [cell.commentLabel2.text sizeWithFont:cell.commentLabel2.font constrainedToSize:CGSizeMake(cell.commentLabel2.frame.size.width, CGFLOAT_MAX) lineBreakMode:cell.commentLabel2.lineBreakMode];
CGFloat commentLabelHeightOffset = (commentLabelComputeSize.height - cell.commentLabel2.frame.size.height > 0) ? (commentLabelComputeSize.height - cell.commentLabel2.frame.size.height) : 0;
cell.commentLabel2.frame = CGRectMake(cell.commentLabel2.frame.origin.x, cell.commentLabel2.frame.origin.y, cell.commentLabel2.frame.size.width, cell.commentLabel2.frame.size.height + commentLabelHeightOffset);
cell.commentLabel2.autoresizingMask = UIViewAutoresizingFlexibleHeight;
cell.commentLabel2.numberOfLines = 0;
} else {
cell.commentLabel.hidden = NO;
cell.commentLabel2.hidden = YES;
}
[CommonUtilities displayStarRatingsWithScore:overallScore starImageViewArray:overallImageViewArray];
return cell;
}
return nil;
}
The isSelected part from heightForRowAtIndexPath does work, and the table cell does visibly expand on tap, but the text remains the same - at least, as tested on iOS 7+ devices.
EDIT: I also logged out the values of cell.commentLabel2.frame, by adding this:
NSLog(#"VenueTabViewController: cellForRow: contains indexpath %#, size: %#", indexPath, NSStringFromCGRect(cell.commentLabel2.frame));
in both the if and else of cellForRowAtIndexPath, and it shows the following:
On first tap:
VenueTabViewController: cellForRow: contains indexpath {length = 2, path = 0 - 1}, size: {{20, 31}, {285, 60.579999999999998}}
On second tap:
VenueTabViewController: cellForRow: contains indexpath {length = 2, path = 0 - 2}, size: {{20, 31}, {285, 21}}
So it does change in size.
What I tried:
I googled this, and found out that [string sizeWithFont:[UIFont systemFontOfSize:15.0f] constrainedToSize:constrainSize lineBreakMode:NSLineBreakByWordWrapping]; has been depreciated. So instead, I replaced the lines relating to it above with:
CGSize labelSize = [text sizeWithAttributes:#{NSFontAttributeName: [UIFont systemFontOfSize:17.0f]}];
CGFloat labelHeight = ceilf(labelSize.height);
Which not only failed to work, it also stopped the cell from expanding, which I thought might be a step backwards.
I also tried adding the following, because why not:
VenueReviewCell *cell = (VenueReviewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell==nil){
cell = [[[NSBundle mainBundle] loadNibNamed:#"ReviewCell" owner:nil options:nil] objectAtIndex:0];
}
[cell.commentLabel sizeToFit];
But it's still a nope.
Then, I simply replaced commentLabelHeightOffset with 100, just to test if anything will change:
cell.commentLabel2.frame = CGRectMake(cell.commentLabel2.frame.origin.x, cell.commentLabel2.frame.origin.y, cell.commentLabel2.frame.size.width, cell.commentLabel2.frame.size.height + commentLabelHeightOffset);
Nothing happened.
EDIT: Here's what I did that finally gained traction - I removed the AutoLayout on the cells, as per the suggestion of saif. And now, while the cells do expand, and the labels along with it, for some reason I get this:
I checked the code, and the X and Y of the label frame aren't changed (just the frame height) and the text has no "new lines" before the actual text.
Can I have some help please?
Try this, Set the frame to desc label in cell for row(depending on text size), and reload the table view when you want to expand the cell.
In cellForRowAtIndexPath
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID forIndexPath:indexPath];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
//code to add desc label
}
CGSize suggestedSize = [descriptionText sizeWithFont:descLabel.font constrainedToSize:CGSizeMake(descLabel.frame.size.width, FLT_MAX) lineBreakMode:descLabel.lineBreakMode];
float padding = 20;
[descLabel setFrame:CGRectMake(padding, CGRectGetMaxY(nameLabel.frame), CGRectGetWidth(tableView.frame)-(2*padding), suggestedSize.height)];
if you are using auto layouts in custom cell then
Keep a back up, and uncheck auto layouts
select iPhone in drop down and select Disable size class
If there is a problem with row height,
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
CGSize suggestedSize = [descriptionText sizeWithFont:descLabel.font constrainedToSize:CGSizeMake(descLabel.frame.size.width, FLT_MAX) lineBreakMode:descLabel.lineBreakMode];
float heightOfRow = CGRectGetMaxY(nameLabel.frame)+suggestedSize.height+5; // height of name label(as it is single line supported) + height of desc label + bottom padding
return heightOfRow;
}
Hope this helps
Try autoresizing:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
VenueReviewCell *cell = (VenueReviewCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
cell.commentLabel.autoresizingMask = UIViewAutoresizingFlexibleHeight;
cell.commentLabel.numberOfLines = 0;
return cell;
}
If you want to continue using autolayout:
-set the numberOfLines to '0'
-Implement the following two TableView methods
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewAutomaticDimension;
}
Working with Self-Sizing Table View Cells Here is a useful reference.
If you're using manual layout then you must set the numberOfLines property of your label to 0, also you will want to call -sizeToFit on the label after setting the text.
You might also need to change some other frames after this accordingly so the label doesn't overlap anything.
If you are using AutoLayout then setting the numberOfLines is still needed but then it depends on your constraints, if you've set the left and right of the label to the super view's left and right then it can infer a maximum width and grow the label vertically.
In any case your screenshot clearly shows that the label is set to have numberOfLines = 1, your cell height looks okay, which is expected since you're calculating that in code with a set width. It's the rendering of the label which is not being triggered. Change numberOfLines to 0 to start with, then in layoutSubviews (if you're doing things manually) you'll want to sizeToFit

Label's frame size does not change in tableView cell

I am working in storyboard. I have View Controller inherited from tableViewVC. In that vc I have cells with one or 2 lines of text. If I have one line, I just assign text to a custom textLabel in custom Cell. If I have 2 lines, I resize the labels frame. But it does not work when the table is loaded. I can see my resized labels in cell only after I scroll tableView up/down. How can I fix it?
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
OptionItem *item = _currentOptionsList[indexPath.row];
static NSString *CellIdentifier = #"OptionSimpleCellIdentifier";
OptionSimpleCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.titleLabel.text = item.title;
cell.haveDetail = item.haveDetailItems;
cell.selectedSimpleOption = item.simpleSelected;
if (item.haveSelectedDetailItem)
{
cell.detailLabel.text = [item.detailItems[item.indexOfSelecteDetaildItem] title];
} else {
cell.detailLabel.text = nil;
cell.detailImageView.image = nil;
}
CGFloat textHeight = [Calculatons getLabelHeightForText:item.title andWidth:225 withFont:kFontListCell withMaxHeight:0];//19 - 39
CGRect rect = cell.titleLabel.frame;
NSLog(#"textHeight = %f cell.height = %f titleLabel.height %f \n",textHeight, cell.frame.size.height, cell.titleLabel.frame.size.height);
if (textHeight > 21)
{
rect.size.height = 41;
cell.titleLabel.frame = rect;
}
//nothing of this not works
[cell.titleLabel layoutIfNeeded];
[cell.titleLabel setNeedsLayout];
[cell.titleLabel setNeedsUpdateConstraints];
[cell.titleLabel setNumberOfLines:0];
return cell;
}
http://s23.postimg.org/8tszefzbf/Screen_Shot_2014_08_27_at_10_01_10_PM.png
After the first screen, i push the VS. second screen is what is shown after i scroll the table up and down.
I need second screen as a result after i push VC.
try using this earlier in the code, right after the cell is initialised instead of after the value is set to the label.
CGFloat textHeight = [Calculatons getLabelHeightForText:item.title andWidth:225 withFont:kFontListCell withMaxHeight:0];//19 - 39
CGRect rect = cell.titleLabel.frame;
NSLog(#"textHeight = %f cell.height = %f titleLabel.height %f \n",textHeight, cell.frame.size.height, cell.titleLabel.frame.size.height);
if (textHeight > 21)
{
rect.size.height = 41;
cell.titleLabel.frame = rect;
}

UITableView lagging when scrolling for chat like app

I have a chat function in the app I am making. Each cell has a UITextView and I need to calculate the **height and width** of each cell. I do that and then cache that data.
Using NSLog I have determined that the data is correctly cached and the height for each row is only being asked for once.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
Message *message = [feedItems objectAtIndex:indexPath.row];
NSString *reuseIdentifier;
if (message.iSentThisMessage) {
reuseIdentifier = #"MeCell";
} else {
reuseIdentifier = #"HostCell";
}
ChatTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath];
// Configure the cell...
cell.textView.text = message.content;
if (message.frame.size.height == 0 && message.frame.size.width == 0) {
CGRect rect = cell.textView.frame;
rect.origin.x = 5;
rect.origin.y = 3;
CGSize size = [self text:message.content
sizeWithFont:[UIFont systemFontOfSize:17.0]
constrainedToSize:CGSizeMake(225.0, CGFLOAT_MAX)];
rect.size.height = size.height
+ cell.textView.textContainerInset.bottom
+ cell.textView.textContainerInset.top;
rect.size.width = [cell.textView sizeThatFits:CGSizeMake(225.0, rect.size.height)].width
+ cell.textView.textContainerInset.left
+ cell.textView.textContainerInset.right;
if (message.iSentThisMessage) {
rect.origin.x = 320 - (rect.origin.y + rect.size.width);
}
cell.textView.frame = rect;
message.frame = rect;
NSLog(#"Not Cached :(");
} else {
cell.textView.frame = message.frame;
NSLog(#"Cached!");
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
Message *message = [feedItems objectAtIndex:indexPath.row];
CGSize size = [self text:message.content
sizeWithFont:[UIFont systemFontOfSize:17.0]
constrainedToSize:CGSizeMake(225.0, CGFLOAT_MAX)];
if (indexPath.row + 1 == feedItems.count)
size.height += 4;
NSLog(#"Height asked for.");
return size.height + 12;
}
Also, one other possibility may be that I am overriding the following method in my custom uitableviewcell class because otherwise it rearranges the contents of my cell.
- (void) layoutSublayersOfLayer:(CALayer *)layer {
}
I can't seem to figure out how to make it not lag!!
Not clear why you're using a text view, but you should change to a label if you can.
Also, don't cache the height in your table delegate method, that's a nasty side effect. Calculate the height up front, either when the message is loaded / received, or on a background thread for batch load.
The text view / label frame should also be relative to the cell, either by auto resizing / layout. So you should never set it explicitly.
On top of that - profile using instruments. This is the only thing that will really tell you what's wrong.

Probleme with height UITableViewCell

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/

UILabel size adjustment within a UITableViewCell loaded from Nib

UILabel within in a Cell contains a NSLocalizedString; varying from a few characters to a paragraph depending on language. The frame of the UILabel sometime does, and sometimes doesn't draw to fit the string length. I believe this is an issue with reuse, but I'm at a loss on how to fix it.
I have a series of five different UITableViewCell subclasses loaded from Nibs (project requirement) in viewDidLoad:
UINib *Cell1Nib = [UINib nibWithNibName:#"customCell1" bundle:nil];
[[self tableView] registerNib:Cell1Nib forCellReuseIdentifier:#"custCell1"];
UINib *Cell2Nib = [UINib nibWithNibName:#"customCell2" bundle:nil];
[[self tableView] registerNib:Cell2Nib forCellReuseIdentifier:#"custCell2"];
//etc.
I have a helper for getting height of the UILabel depending on the text used:
- (CGFloat)getTextHeight:(NSString *)locStr forLabelWidth:(CGFloat)w {
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, w, 110)];
label.numberOfLines=0;
label.lineBreakMode=NSLineBreakByCharWrapping;
label.text = locStr; // highly variable & already localized
label.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
CGSize maxSize = CGSizeMake(w, CGFLOAT_MAX);
CGSize requiredSize = [label sizeThatFits:maxSize];
label = nil; // ARC paranoia
return requiredSize.height;
}
In heightForRowAtIndexPath I call getTextHeight:forLabelWidth:, using it to determin the cell height and storing the result into an NSMutableArray called, labelHeightforRow. So far, everything works great.
I create the table as such:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = nil;
DLX_CellDescriptor *desc = [[DLX_CellDescriptor alloc] initWithRow:indexPath.row];
//DLX_CellDescriptor describes attributes for cell at index , essentially a list of strings
CGFloat helpTextHeight = [[labelHeightforRow objectAtIndex:indexPath.row] floatValue];
if ([desc.nibToUse caseInsensitiveCompare:#"custCell1"] == NSOrderedSame ) {
DLX_CustCell1 *currCell = (DLX_CustCell1 *)[self.tableView dequeueReusableCellWithIdentifier:#"custCell1"];
CGPoint origin = currCell.theLabel.frame.origin;
CGFloat w = currCell.theLabel.frame.size.width;
currCell.theLabel.frame = CGRectMake(origin.x, origin.y, w, helpTextHeight);
currCell.theLabel.text = desc.localizedText;
currCell.theLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
currCell.tag = indexPath.row;
cell = currCell;
} else if ([desc.nibToUse caseInsensitiveCompare:#"custCell2"] == NSOrderedSame ) {
DLX_CustCell2 *currCell = (DLX_CustCell2 *)[self.tableView dequeueReusableCellWithIdentifier:#"custCell2"];
CGPoint origin = currCell.theLabel.frame.origin;
CGFloat w = currCell.theLabel.frame.size.width;
currCell.theLabel.frame = CGRectMake(origin.x, origin.y, w, helpTextHeight);
currCell.theLabel.text = desc.localizedText;
currCell.theLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
currCell.tag = indexPath.row;
cell = currCell;
} // for about 26 rows of 5 different non-identical sytles
// simplified in this example
return cell;
}
This issue is that when the initial TableView is created, the UILabel is the height specified in the Nib: truncating extra long text and giving a large white space below (from the correct cell height adjustment). When the table is redrawn, the UILabel turns into the correct height specified in the code; showing the entire string. Then, if the cell is recreated; say, after it has scrolled off the screen and another of it's cell type has drawn, the long-text label is using the truncating height from the Nib again.
I tried putting layoutSubviews into the custom UITableViewCell (customCell1.m, for example) as such:
- (void)layoutSubviews {
NSInteger currCell = self.tag;
DLX_CellDescriptor *desc = [[DLX_CellDescriptor alloc] initWithRow:currCell];
CGPoint origin = theLabel.frame.origin;
CGSize size = theLabel.frame.size;
CGFloat textHeight = [self getTextHeight:desc.localizedText forLabelWidth:size.width];
theLabel.frame = CGRectMake(origin.x, origin.y, size.width, textHeight);
[super layoutSubviews];
}
But that had the effect of immutably ensuring that the height from the Nib was used; even though upon inspection, textheight was correct (and, for some languages, much larger then the Nib's height.)
Since that your cell is relatively simple, one easy way to solve your problem is don't use reuse. Just load the nib file from bundle. Delete those registerNib related code. And do it like this:
NSString *reuseIdentifier = #"DistrictCellReuseIdentifier";
DistrictCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];
if (cell == nil) {
cell = [[NSBundle mainBundle] loadNibNamed:#"DistrictCell" owner:self options:nil][0];
}

Resources