Autoresizing of UILabels in a UITableViewCell
I am adding my own UILabel
s to the contentView
of a UITableViewCell
because I need more control over the layout than the default UITableViewCellStyles provide. In essence I want the detailLabel have priority over the textLabel so the textLabel gets truncated.
I have the following code in my UITableViewController
:
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString * const kCellIdentifier = @"CustomCell";
UITableViewCell * cell =
[tableView dequeueReusableCellWithIdentifier:kCellIdentifier];
UILabel * titleLabel, * dateLabel;
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:kCellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
titleLabel = [[[UILabel alloc] init] autorelease];
titleLabel.tag = kTitleLabelTag;
titleLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
dateLabe开发者_开发百科l = [[[UILabel alloc] init] autorelease];
dateLabel.tag = kDateLabelTag;
dateLabel.textColor = [UIColor blueColor];
dateLabel.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[cell.contentView addSubview:titleLabel];
[cell.contentView addSubview:dateLabel];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)configureCell:(UITableViewCell *)pCell
atIndexPath:(NSIndexPath *)pIndexPath
{
const float kHeight = 44.0, kLeftIndent = 8.0, kOverallWidth = 293.0,
kGap = 1.0;
UILabel * titleLabel, * dateLabel;
titleLabel = (UILabel *)[pCell.contentView viewWithTag:kTitleLabelTag];
dateLabel = (UILabel *)[pCell.contentView viewWithTag:kDateLabelTag];
NSString * dateText = @"9:39 AM";
// Calculate the size of dateLabel
CGSize dateSize = [dateText sizeWithFont:[dateLabel font]
constrainedToSize:CGSizeMake(kOverallWidth, kHeight)];
const float dateXPos = kOverallWidth - dateSize.width;
dateLabel.frame = CGRectMake(dateXPos, 0.0, dateSize.width, kHeight);
titleLabel.frame = CGRectMake(kLeftIndent, 0.0,
dateXPos - kLeftIndent - kGap, kHeight);
titleLabel.text = @"Some potentially very long text which will be wrapped.";
dateLabel.text = dateText;
pCell.contentView.backgroundColor = [UIColor purpleColor];
}
The code above produces incorrect results. When the table view is initially shown, it looks like figure 1) in this image of the renderings.
So there is a unwanted gap on the right of all the dateLabel
s. (the purple background is just for better visibility what is going on)
When dragging the tableview up like in 2) in the image, it then bounces back and looks like 3).
The first row has now exactly the layout I wanted and which calculated in configureCell:atIndexPath:
. I guess this behavior happens because the cells get re-used and then configured again.
So it feels like I am missing some kind of initialization, I have tried calling setNeedsLayout
and layoutSubviews
of pCell
and pCell.contentView
but never achieved an initial correct rendering.
Only when I set the autoresizingMask
of titleLabel
and dateLabel
to UIViewAutoresizingNone
I get a correct initial rendering, then however the swipe to delete does not work because the delete button gets rendered over the dateLabel
.
What do I have to change in my code so that all cells get rendered initially like the first cell in the third picture?
Thanks!
PS: I would like to have inlined the pictures but unfortunately I do not have enough reputation for that.
A good, and maybe simpler way to do this is to:
First Create a custom UITableViewCell subclass which you can setup using Interface Builder. If "MyTableViewCell" is your custom cell view you initialize it in CellForRowAtIndexPath like this:
MyTableViewCellClass *cell = (MyTableViewCellClass *)[tableView dequeueReusableCellWithIdentifier:@"MyTableViewCellClass"] autorelease];
if (!cell)
cell = [[[MyTableViewCellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"MyTableViewCellClass"] autorelease];
// Call specific methods on your cell to pass information to it, not for display
[cell setProperties:...];
Then implement the layoutSubviews method in your custom UITableViewCell subclass. For instance:
-(void) layoutSubviews
{
// You must call this first to make sure your cell gets current parent information
[super layoutSubviews];
// Retrieve the content view bounds. This will include the edit symbols when present (delete button and ordering symbol
float inset = 5.0;
CGRect bounds = [[self contentView] bounds];
// Keep on going here with your own view layout.
}
Doing this you basically separate the cell model (CellForRowAtIndexPath) from the cell view (your custom implementation of cell drawing). If you later change the implementation (layout) of your cell you can do this easily simply by changing your cell layout without worrying about the CellForRowAtIndexPath method.
If you work with a storyboard , you should disable the "Use Auto Layout" in the File Inspector!
Then set the cell's property autoresizesSubviews
- (void)awakeFromNib
{
// Initialization code
self.autoresizesSubviews=YES;
}
The final step is configure the frame of the Label , overriding the method layoutSubviews of the UITableViewCell class
-(void)layoutSubviews{
[super layoutSubviews];
CGFloat top=VerticalPadding;
CGFloat left=HorizentalPadding;
CGFloat width=CGRectGetWidth(self.frame)-2*HorizentalPadding;
CGFloat height=CGRectGetHeight(self.frame)-2*VerticalPadding;
CGRect rect=CGRectMake(left, top, width, height);
self.Label.frame=rect;
}
精彩评论