I got totally hosed this week trying to add a subview to a UITableViewCell. The cool thing is that I learned a lot.
I created a custom UITableViewCell that called FeedCommentTableViewCell class. Below is the working code:
#import "FeedCommentTableViewCell.h"
#import "Settings.h"
@implementation FeedCommentTableViewCell
- (void)layoutSubviews {
[super layoutSubviews];
CGRect labelFrame = CGRectMake(LEFT_PAD, 0, (self.contentView.bounds.size.width - 2 * LEFT_PAD), self.contentView.bounds.size.height);
self.commentLabel.frame = labelFrame;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
_commentLabel = [[STTweetLabel alloc] initWithFrame:CGRectZero];
_commentLabel.font = COMMENT_FONT;
_commentLabel.numberOfLines = 0;
_commentLabel.lineBreakMode = NSLineBreakByWordWrapping;
[self.contentView addSubview:self.commentLabel];
}
return self;
}
@end
A few lessons learned:
1. initWithStyle is called only when the cell is created and thus will be used multiple times. So I set the frame to zero realizing that this cell will dynamically change in size based on a function I wrote in the UITableViewController subclass.
2. Based on experiments suggested by
this post, I learned that tableview:CellForRowAtIndexPath will get called first and at the very last layoutSubviews will be called as the cell is displayed. This is the place to set the size of the subviews based on the size of the cell.
3. I was setting my (commentLabel in the example above) subview's frame based on the cell's frame (self.frame). This was a no-no.
Expanding on number 3.
Let's say my layoutSubviews method wanted the commentLabel to be the same size as the cell itself. I originally did something like the following:
- (void)layoutSubviews {
[super layoutSubviews];
self.commentLabel.frame = self.contentView.frame
}
This would render the first cell perfect, but as I scrolled and scrolled back up I saw problems. You see, self.contentView.frame is the coordinates of the cell in the parent view's coordinate system. We want to assign the frame of the commentLabel to be set to the coordinates based cell's subview itself. Simply moving this to something like:
- (void)layoutSubviews {
[super layoutSubviews];
self.commentLabel.frame = self.contentView.bounds;
}
Adds this subview into the coordinate system of the contentView, which is what we want!
Now I'm sure Autolayout and using Storyboards make this easier, but I've found that for more complex UITableViewCells, laying it out in code seems to be a lot easier to debug.
Moving on to the rest of the project now that that bug is under my belt!