views:

5955

answers:

4

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)

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

A: 

Why not try to resize your cells so they dont have that extra space? So fit the cell better to the label...

Daniel
please look at updated picture
Igor
+1  A: 

However you're sizing your cells, you should do it with the various sizing methods of NSString. That way, you can determine exactly how tall to make the cell and avoid the whitespace.

Jeff Kelley
+12  A: 

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
Chris Garrett
Great answer, worked perfectly. Nice touch: replace 4.0 with 12.0 if detailTextLabel.text == nil to center the textLabel vertically in the view when there is no detailText for the cell.
Gerry
It's woks like a charm!
wal
A: 

If it turns out that the textLabel and detailTextLabel are laid out using autoresizing masks, maybe you can do this when you return the cell:

cell.textLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin;
cell.detailTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

If this works, it's a bit easier than subclassing the cell. I haven't tried it though.

Daniel Dickison
Of course it's easy, but does not make a job. layoutSubviews-overriding is the right way.
slatvick