views:

1936

answers:

2

Hi everyone,

I am building a custom, in-application settings view based on UITableViewCellStyle1 (or so). I'm trying to dynamically calculate the width of the left label (title) of a cell in order to determine how wide my text field on the right can be. When I launch the app in the simulator and the view loads, the width of the title labels is zero UNTIL i scroll down the view and a cell isn't visible, then when I scroll back up the size adjusts as expected. I believe this might have to do something with cell reusage, but I don't know how it works exactly. And what I need is simply the title labels in the cells to have their correct width is when the view loads in the first place, not after they have gone out of sight one time.

- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
  {
      static NSString* reuseIdentifier = @"SettingsCell";

UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier];

if ( !cell )
{ 
 cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier] autorelease];
 [cell setBackgroundColor:[UIColor baeDarkGrayColor]];


 UILabel* cellLabel = [cell textLabel];
 [cellLabel setTextColor:[UIColor whiteColor]];
 [cellLabel setBackgroundColor:[UIColor clearColor]];

 [cell setUserInteractionEnabled:YES];
 [cell setSelectionStyle:UITableViewCellSelectionStyleGray];
}

// Populate cell with corresponding data.
NSDictionary* tableSection = [_tableData objectAtIndex:indexPath.section];

// Set the label
UILabel* textLabel = [cell textLabel];
NSString* labelString = [[tableSection objectForKey:@"itemTitles"] objectAtIndex:indexPath.row];
[textLabel setText:labelString];

   //   CGSize constrainedSize;
  //    constrainedSize.width = MAXFLOAT;
 // constrainedSize.height = MAXFLOAT;

CGSize textLabelSize = [textLabel.text sizeWithFont:textLabel.font /*constrainedToSize:constrainedSize*/];

NSLog(@"text label width: %f", textLabelSize.width); 


// Set the accessory view
BAESettingsTableCellAccessoryType accessoryType = [[[tableSection objectForKey:@"itemAccessories"] objectAtIndex:indexPath.row] integerValue];
switch ( accessoryType )
{
 case BAESettingsTableCellAccessoryDisclosureIndicator:
 {
  UIImageView* disclosureView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"AccessoryDisclosure.png"]];
  [cell setAccessoryView:disclosureView];
  [disclosureView release];
  break;
 }
 case BAESettingsTableCellAccessoryOnOffSwitch:
 {
  UISwitch* onOffSwitch = [[UISwitch alloc] initWithFrame:CGRectZero];
  [onOffSwitch setOn:YES];
  [cell setAccessoryView:onOffSwitch];
  [onOffSwitch release];
  break;
 }
 case BAESettingsTableCellAccessoryNone:
  // default:
  // break;
 {

  CGRect cellFrame = [cell frame];

  float detailTextFieldWidth = cellFrame.size.width - ( textLabelSize.width + 50 );
  float detailTextFieldHeight = cellFrame.size.height - 1;

  NSLog(@"detail text field calculated frame width, height, %f, %f", detailTextFieldWidth, detailTextFieldHeight);


  CGRect frame = CGRectMake(cellFrame.origin.x, cellFrame.origin.y, detailTextFieldWidth, detailTextFieldHeight);


  UITextField* textField = [[UITextField alloc] initWithFrame:frame];
  NSString* detailLabelString = [[tableSection objectForKey:@"itemDetailStrings"] objectAtIndex:indexPath.row];
  textField.text = detailLabelString;
  textField.textColor = cell.detailTextLabel.textColor;
  textField.textAlignment = UITextAlignmentRight;
  textField.borderStyle = UITextBorderStyleRoundedRect;
  [cell setAccessoryView:textField];
  [textField release];
  break;
 }

}

return cell;
   }

Thanks, Lex

+3  A: 

Explicitly setting the font solves your problem.

CGSize textLabelSize = [textLabel.text sizeWithFont:[UIFont systemFontOfSize:17]];

Gory Detals:
When the tableview first loads, this snippet returns zero width due to the font size being 0.

[textLabel.text sizeWithFont:textLabel.font]

I figured this out by displaying the point size of the cell font.

NSLog(@"font size: %f", cell.textLabel.font.pointSize);

The point size was zero until the cell went off screen and came back, just as you described.

bentford
A: 

I found the same issue, but I've found a workaround. FYI I've raised an bug with Apple (Bug ID# 7535066). Lex, in your example, if you use cell.font instead of textLabel.font, it should work, although you will get a compiler warning, as this is a deprecated method call. I'm not sure if you'll be able to see the details of the bug I raised, so I'm pasting the details here:

iPhone SDK 3.1.2 (7D11) NSString UIKit Additions method sizeWithFont returns nil

SUMMARY I am decorating UITableViewCells in the UITableView delegate method:

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

I wish to find length of the text already in the cell, to correctly format the new view, so I am calling the NSString UIKit Additions method:

  • (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

When I use cell.textLabel.font for the font argument, it always returns an empty CGSize

IF I use the DEPRECATED method, cell.font for the argument, it DOES return the CGSize value as expected.

STEPS TO REPRODUCE 1. Create a UITableViewController with a TableView, and populate it with some sample data 2. In the stubbed method cellForRowAtIndexPath, after the comment //Set up the cell, and where the cell.textLabel.text is populated, put the following:

  
 CGSize size = [cell.textLabel.text sizeWithFont:[[cell textLabel] font] constrainedToSize:CGSizeMake(320, 480)];
 NSLog(@"cell frame: %f %f", size.width, size.height);

 CGSize size2 = [cell.textLabel.text sizeWithFont:[cell font] constrainedToSize:CGSizeMake(320, 480)];
 NSLog(@"DEPRECATED cell frame: %f %f", size2.width, size2.height);

EXPECTED RESULTS

If anything, you would expect the call that uses the Deprecated method to retrieve the font, to fail, or at least both to return the same result.

ACTUAL RESULT:

2010-01-12 22:06:36.645 PrefTest[9659:207] cell frame: 0.000000 0.000000 2010-01-12 22:06:36.646 PrefTest[9659:207] DEPRECATED cell frame: 88.000000 24.000000

WORKAROUND & ISOLATION:

As noted, use the deprecated method to get the font. But it gets stranger!

Reverse the two methods I gave above:

 
 CGSize size2 = [cell.textLabel.text sizeWithFont:[cell font] constrainedToSize:CGSizeMake(320, 480)];
 NSLog(@"DEPRECATED cell frame: %f %f", size2.width, size2.height);

    CGSize size = [cell.textLabel.text sizeWithFont:[[cell textLabel] font] constrainedToSize:CGSizeMake(320, 480)];
 NSLog(@"cell frame: %f %f", size.width, size.height);

The results are now:

2010-01-12 22:06:36.645 PrefTest[9659:207] cell frame: 88.000000 24.000000 2010-01-12 22:06:36.646 PrefTest[9659:207] DEPRECATED cell frame: 88.000000 24.000000

It seems that just referencing [cell font] is enough to force [[cell textLabel] font] to work correctly.

Gene M.