Iphone – Labels aligning in UITableViewCell

cocoa-touchiphoneuitableview

I use UITableView with cells created using UITableViewCellStyleSubtitle. Every cell's height is dynamically adjusted using the

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

delegate method.

The problem you can see on the picture

(note: image updated)

http://img.skitch.com/20090715-g7srxgee2d7fhi5rab2wufrdgm.png

How to set up align of textLabel and detailTextLabel to the top of the cell? (I really don't wont to do it by subclassing UITableViewCell and overriding layoutSubviews)

Thanx

Best Answer

Well, this one cost me an afternoon, but I think I figured it out. As far as I can tell, this appears to be a bug in how UITableViewCell is laying out the textLabel and detailTextLabel. When you set the row height, it seems to allocate equal height to the two labels, which means that you get exactly the behavior you're seeing above, even though detailTextLabel needs more room. Here are the two things I did to fix the problem. I had to subclass UITableViewCell to fix it, but it's a minimal amount of code.

First, make sure you're calculating the height of each row properly. Put this method into your table view delegate. Replace the font methods with your own:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
   NSString *cellDetailText = [[self itemForIndexPath: indexPath] detailDescription];
   NSString *cellText = [[self itemForIndexPath: indexPath] description];
   // The width subtracted from the tableView frame depends on:
   // 40.0 for detail accessory
   // Width of icon image
   // Editing width
   // I don't think you can count on the cell being properly laid out here, so you've
   // got to hard code it based on the state of the table.
   CGSize constraintSize = CGSizeMake(tableView.frame.size.width - 40.0 - 50.0, CGFLOAT_MAX);
   CGSize labelSize = [cellText sizeWithFont: [self cellTextLabelFont] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
   CGSize detailSize = [cellDetailText sizeWithFont: [self cellDetailTextLabelFont] constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];

   CGFloat result = MAX(44.0, labelSize.height + detailSize.height + 12.0); 
   return result;
}

Then, subclass UITableViewCell and override layoutSubviews:

#import "UITableViewCellFixed.h"


@implementation UITableViewCellFixed
- (void) layoutSubviews {
   [super layoutSubviews];
   self.textLabel.frame = CGRectMake(self.textLabel.frame.origin.x, 
                                      4.0, 
                                      self.textLabel.frame.size.width, 
                                      self.textLabel.frame.size.height);
   self.detailTextLabel.frame = CGRectMake(self.detailTextLabel.frame.origin.x, 
                                           8.0 + self.textLabel.frame.size.height, 
                                           self.detailTextLabel.frame.size.width, 
                                           self.detailTextLabel.frame.size.height);
}
@end
Related Topic