Showing posts with label uitableview. Show all posts
Showing posts with label uitableview. Show all posts

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.

Friday, September 25, 2009

UITableView, custom cells, and editting

I had a little problem ( and still have one left) related to using a custom cell in a UITableView and trying to get it to do nice things when editting. Like cells sliding right when going into table edit mode and truncating the end when the "delete" button shows up. I have managed to get it working and looking good, except for the case of cell edit mode:

  1. This seems like a lot of work, and I wonder if I am missing something that would make it easier.
  2. The main problem I am having is determining the state of things. Particularly when the table level edit display is on and when the cell level edit display/confirmation is on

  3. The resulting code ends up with if you swipe a table entry, it shifts right just like for the table level edit. Irritating.


    1. ///////////////////////////////////////////////////
    2. //
    3. ///////////////////////////////////////////////////
    4. - (void) layoutSubviews
    5. {
    6. CGRect frame;
    7. CGRect cellFrame = self.frame;
    8. CGRect contentFrame = self.contentView.frame;
    9. UITableView* table = (UITableView*) [self superview];
    10. BOOL tableEditting = table.editing;
    11. BOOL isedit = self.editing;
    12. BOOL cellEditting = self.showingDeleteConfirmation;
    13. // NSInteger indentLevel = self.indentationLevel;
    14. // CGFloat indentWidth = self.indentationWidth;
    15. CGFloat leftOffset = 0;
    16. if (tableEditting)
    17. {
    18. leftOffset = 35;
    19. }
    20. CGFloat rightOffset = 0;
    21. if (cellEditting)
    22. {
    23. rightOffset = 80;
    24. }
    25. frame = topImage.frame;
    26. frame = bottomImage.frame;
    27. frame.origin.x = 0;
    28. frame.origin.y = cellFrame.size.height - 5;
    29. bottomImage.frame = frame;
    30. if (hasAvatar)
    31. {
    32. frame.origin.x = frame.origin.y = 6;
    33. frame.size.height = frame.size.width = 45;
    34. cellAvatarView.frame = frame;
    35. }
    36. else
    37. {
    38. cellAvatarView.frame = CGRectZero;
    39. }
    40. //
    41. frame.origin.y = 5;
    42. frame.size.height = cellFrame.size.height-10;
    43. if (hasAvatar)
    44. {
    45. frame.origin.x = 57;
    46. frame.size.width = cellFrame.size.width - (57 + leftOffset + rightOffset);
    47. }
    48. else
    49. {
    50. frame.origin.x = 6;
    51. frame.size.width = cellFrame.size.width - (6 + leftOffset + rightOffset);
    52. }
    53. cellLabelView.frame = frame;
    54. frame.origin.x = leftOffset;
    55. frame.origin.y = 0;
    56. frame.size.height = cellFrame.size.height;
    57. frame.size.width = cellFrame.size.width - (leftOffset + rightOffset);
    58. self.contentView.frame = frame;
    59. // }//end if labelview
    60. }


    Addendum: My answer, which makes me feel dirty and bad about myself, was to subclass UITableView and add a flag that could be accessed in the cell layoutSubviews that I could set when I entered/exited table edit mode. My first impulse was to override setEditing:animated but it turns out that it gets called when the swipe is detected. Which makes sense in light of things. Not happy about how that works though.