I'm constructing a UITableView with variable height custom table cells, their height determined by the size of a contained multi-line UILabel. I've got the tableView:heightForRowAtIndexPath:
delegate method wired up and calculating the final height correctly using sizeWithFont:constrainedToSize:
.
I've run across strange issue: by the time the data source method tableView:cellForRowAtIndexPath:
is called, the correct per-row height has already been determined as described above, but the frame of the cell does not match that height. Instead, the frame.size.height
property of the cell is the default cell height of the table view (86 px, as I've set it in Interface Builder, the correct height when the contained UILabel has just one line of text), instead of being the height that tableView:heightForRowAtIndexPath:
determined correct for that index path.
I'm producing the cells in cellForRowAtIndexPath:
using dequeuing, that is,
// Using storyboards, this never returns nil, no need to check for it
CustomCell *cell = (CustomCell *)[tableView dequeueReusableCellWithIdentifier:@"SomeIdentifier"];
NSLog(@"%f", cell.frame.size.height); // 86, not correct if the cell contains a multi-line UILabel
It seems, then, that whatever iOS is doing behind the scenes, the dequeuing is not setting the frame property of the cell to match the calculated height. This in itself is not that surprising, dequeuing concerns itself with cell instances, not their geometry. The cells are rendered correctly, though, so the height property is being set somewhere, but it happens after cellForRowAtIndexPath:
.
So: when I initially populate the table view, cell.frame.size.height
is 86 for all the cells as they appear for the first time when I scroll the list downwards. Since the correct geometry is set sometime after the first cellForRowAtIndexPath:
for each row before it's displayed, when I scroll back up, the height property is correct for each cell that comes back into view after being reused.
After this I can scroll the table view back and forth at will, and the height property remains correct for each cell from that point on.
What's the correct way of getting the correct cell height the first time around, before any dequeue-based reuse happens? I need this to do a bit of re-positioning of the subviews of the table cell. Do I need to manually call heightForRowAtIndexPath:
in cellForRowAtIndexPath:
and then manually set the frame of the freshly created CustomCell instance to match that height? This seems redundant, and I'd need to create a mechanism to detect when the cell is created for the first time with the wrong frame height vs. when it is dequeued with the correct frame height later to avoid this redundancy.
So, if someone can shed some light into what the logic is behind this, I'd appreciate it.