13

I am using xib & auto layout to construct my custom cell,in my cell ,there is a multi line label. an in the tableview's heightForRowAtIndexPath, i will use enter image description here

1 dequeueReusableCellWithIdentifier to get a cell

2 then call [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] to get the correct height .

enter image description here But in debug , I found that when heightForRowAtIndexPath is called ,my cell's width is not the tableview's width, the cell's width is the same as the width of xib file (because in xcode6 ,you can set the xib size to any). so the height got from systemLayoutSizeFittingSize is not correct . how can I fix this problem to get the correct cell height

the size got from the systemLayoutSizeFittingSize: is not correct ,this size may have the width 340+ (while the device is iPhone5 whose width is 320),and the 340+ is accually the cell's xib file 's width

Finally, I got the solution ,thanks Ashish Gabani for help ,in fact ,the solution include 2 step: 1 reset the cell frame to your tableView size 2 call cell's layoutSubViews before you calling systemLayoutSizeFittingSize, and In your custom cell ,you need to rewrite the layoutSubViews method. Here is the code for fix this problem , I use the red square to mark them ,enjoy it

enter image description here enter image description here

ximmyxiao
  • 2,622
  • 3
  • 20
  • 35

1 Answers1

16

You Can Solve this Issue by Passing your Cell Height like as

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Determine which reuse identifier should be used for the cell at this index path,
// depending on the particular layout required (you may have just one, or may have many).
NSString *reuseIdentifier = ...;

// Dequeue a cell for the reuse identifier.
// Note that this method will init and return a new cell if there isn't one available in the reuse pool,
// so either way after this line of code you will have a cell with the correct constraints ready to go.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

// Configure the cell with content for the given indexPath, for example:
// cell.textLabel.text = someTextForThisCell;
// ...

// Make sure the constraints have been set up for this cell, since it may have just been created from scratch.
// Use the following lines, assuming you are setting up constraints from within the cell's updateConstraints method:
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

// If you are using multi-line UILabels, don't forget that the preferredMaxLayoutWidth needs to be set correctly.
// Do it at this point if you are NOT doing it within the UITableViewCell subclass -[layoutSubviews] method.
// For example:
// cell.multiLineLabel.preferredMaxLayoutWidth = CGRectGetWidth(tableView.bounds);

return cell;
 }

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Determine which reuse identifier should be used for the cell at this index path.
NSString *reuseIdentifier = ...;

// Use a dictionary of offscreen cells to get a cell for the reuse identifier, creating a cell and storing
// it in the dictionary if one hasn't already been added for the reuse identifier.
// WARNING: Don't call the table view's dequeueReusableCellWithIdentifier: method here because this will result
// in a memory leak as the cell is created but never returned from the tableView:cellForRowAtIndexPath: method!
UITableViewCell *cell = [self.offscreenCells objectForKey:reuseIdentifier];
if (!cell) {
    cell = [[YourTableViewCellClass alloc] init];
    [self.offscreenCells setObject:cell forKey:reuseIdentifier];
}

// Configure the cell with content for the given indexPath, for example:
// cell.textLabel.text = someTextForThisCell;
// ...

// Make sure the constraints have been set up for this cell, since it may have just been created from scratch.
// Use the following lines, assuming you are setting up constraints from within the cell's updateConstraints method:
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];

// Set the width of the cell to match the width of the table view. This is important so that we'll get the
// correct cell height for different table view widths if the cell's height depends on its width (due to
// multi-line UILabels word wrapping, etc). We don't need to do this above in -[tableView:cellForRowAtIndexPath]
// because it happens automatically when the cell is used in the table view.
// Also note, the final width of the cell may not be the width of the table view in some cases, for example when a
// section index is displayed along the right side of the table view. You must account for the reduced cell width.
cell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds));

// Do the layout pass on the cell, which will calculate the frames for all the views based on the constraints.
// (Note that you must set the preferredMaxLayoutWidth on multi-line UILabels inside the -[layoutSubviews] method
// of the UITableViewCell subclass, or do it manually at this point before the below 2 lines!)
[cell setNeedsLayout];
[cell layoutIfNeeded];

// Get the actual height required for the cell's contentView
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

// Add an extra point to the height to account for the cell separator, which is added between the bottom
// of the cell's contentView and the bottom of the table view cell.
height += 1.0f;

return height;
 }

// NOTE: Set the table view's estimatedRowHeight property instead of implementing the below method, UNLESS
// you have extreme variability in your row heights and you notice the scroll indicator "jumping" as you scroll.
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Do the minimal calculations required to be able to return an estimated row height that's
// within an order of magnitude of the actual height.
// For example:
if ([self isTallCellAtIndexPath:indexPath]) 
{
    return 350.0f;
} else {
    return 40.0f;
}
}

You can also Find the Solution From Here Link

Community
  • 1
  • 1
  • 2
    because my cell's height is dynamic , So I was doing like this ,use systemLayoutSizeFittingSize to get my cell's height , and return the height in heightForRowAtIndexPath.But just as I said ,in the heightForRowAtIndexPath , the cell's width is not correct ,so the height i got is also not correct:( – ximmyxiao Dec 02 '14 at 09:19
  • Please Can you pest your Code? that you write in your Project. –  Dec 02 '14 at 09:32
  • OK ,I have post the code ,pls have a look ,the problem is at the green line: the size 's width can be wider than my device screen – ximmyxiao Dec 02 '14 at 09:52
  • @ximmyxiao in method tableView cellForRowAtIndexPath what you write? –  Dec 02 '14 at 10:01
  • in cellForRowAtIndexPath ,I just create my custom cell. and my custom cell is connected with a xib , the most important subview of cell is a multi line label .I am sure it's this multiline label cause systemLayoutSizeFittingSize the problem. – ximmyxiao Dec 02 '14 at 10:08
  • @ximmyxiao show my updated answer and you can also set estimated size like as self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = 44.0; –  Dec 02 '14 at 10:20
  • i have edit the code (as the new screen shot ) ,but it seems like the systemLayoutSizeFittingSize still got a bigger width than my screen width :( am I anything wrong ? – ximmyxiao Dec 02 '14 at 10:31
  • I print the cell frame and the size i got cell:{{11.5, 0}, {320, 222}} size :{342, 159.5} – ximmyxiao Dec 02 '14 at 10:37
  • Instead of adding 1 extra pixel for the separator, you can simply calculate the height based on the cell rather than the contentView and ceil the resulting float as follows: return ceilf([cell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height); – jomafer Apr 22 '15 at 10:49
  • i have exactly the same issue, did you find a workaround ? – mahieddine Sep 05 '15 at 13:35
  • @mahieddine did u solved the problem ? in fact the key points is :1) use the correct width to calculate cell height in heightForRowAtIndexPath 2) use the correct preferrdMaxLayoutwidth as I depict above – ximmyxiao Sep 18 '15 at 02:41
  • Hi @ximmyxiao i resolved it by computing my custom view height which is inside the custom cell instead of computing the cell height, because the size returned for the content view was wrong (something like 10000 * 20000) and i don't know why. i used preferred maxlayoutwidth and ten thousand work around and nothing fixed the issue, i think i just have a complex view, what do you mean by use the correct width ? – mahieddine Sep 18 '15 at 07:49
  • @mahieddine If you use xib to construct width in xcode6 or later , when the cell is decked from the tableview , the width is the xib file 's width ,not the tableview's width , so you need to set the cell 's width to the tableview's width ,before the height calculation – ximmyxiao Sep 21 '15 at 02:27
  • test questions answer – ximmyxiao Jun 21 '16 at 09:19