Thursday, October 29, 2009

UITableView cells are not exactly treated like regular views

I was having a problem that in some cases the selection rect was not matching up with the actual cell bounds in a list with variable height custom cells. The selection rect height was simply wrong in seemingly random ways. But I figured it out and it is because the table is doing some things under the covers.

I had things set up so that the custom cell constructor would add all the subviews it needed and where possible set the positions and sizes. Generally the bottom edge of the cell would be defined the a multiline UILabel that could hold a varying amount of text. So in tableView:cellForRowAtIndexPath I would allocate the cell (when needed) and then call a method on the cell that would populate its data with a passed in object. I also defined layoutSubviews that could make needed adjustments based on the data and also set the height of the multiline UILabel. I also provided a class level method that would return the height of the cell for given text so that I could set the same height for the layout and for tableView:heightForRowAtIndexPath.

It turns out that is the wrong thing to do with table cells. It appears that when the cell in returned to the table, it takes a height right then and saves it aside for the the selection rectangle. layoutSubviews isn't called until later so the heights can mismatch sometimes.

The solution was to call the layoutSubviews code (and not have layoutSubview defined) after I populated the cell but before it is returned to the tableView.

I can understand why it is this way, but I think it should be made explicitly clear that the cell you return for tableView:cellForRowAtIndexPath must match the height you returned earlier.

No comments:

Post a Comment