Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView cell.contentView.bounds.size.width Changes With Cell Reuse

I use cell.contentView.bounds.size.width to calculate the position of a text field in a UITableView cell. When the cell is created, debug code reports the width as 302. When the cell scrolls off the screen and then back on, the debug code reports that the it is 280--every time. It doesn't seem to want to go back to 302 and stays stuck at 280. The net result is that the text field gets put in the wrong place the second time the field is put into the cell's contentView, though it was put in the right place the first time.

I figure 22 is significant somehow, but I don't know what it is. Guessing it might be the disclosure arrow, I moved the "clear the cell" code up front of the width determination, including setting the accessory to nada.

Can anybody tell me what's going on here?

The code (with irrelevant--that I know of--stuff snipped out) looks like this:

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    NSUInteger section = [indexPath section];
    NSUInteger row = [indexPath row];

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }


    // Configure the cell.

    while( [cell.contentView.subviews count] ){
        id subview = [cell.contentView.subviews objectAtIndex:0];
        [subview removeFromSuperview];  
    }
    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;

8< snip!

    CGFloat theCellWidth = cell.contentView.bounds.size.width - 44.0;
    CGFloat theLineHeight = [[UIFont boldSystemFontOfSize: [UIFont labelFontSize]+1.0] lineHeight]; 

    NSLog(@"cell.contentView.bounds.size.width %1.0f",cell.contentView.bounds.size.width);

    if (0==section) {
        switch (row) {
            case 2:
                while( [cell.contentView.subviews count] ){
                    id subview = [cell.contentView.subviews objectAtIndex:0];
                    [subview removeFromSuperview];  
                }
                cell.selectionStyle = UITableViewCellSelectionStyleNone;
                cell.textLabel.text = @" ";
                cell.detailTextLabel.text = @"The Age";
                theAgeTextField.frame = CGRectMake(10.0, 2.0, theCellWidth, theLineHeight);
//                NSLog(@"cell.contentView %@",cell.contentView);
                theAgeTextField.text = theAge;
                theAgeTextField.font = [UIFont boldSystemFontOfSize: [UIFont labelFontSize]+1.0];
                theAgeTextField.keyboardType = UIKeyboardTypeDecimalPad;
                theAgeTextField.borderStyle = UITextBorderStyleNone;
                theAgeTextField.userInteractionEnabled = NO;
                [cell.contentView addSubview:theAgeTextField];
                cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
                break;

8< snip! (lots of closing braces and other stuff omitted)

    return cell;
}

Want to try this one at home, boys and girls?

Start with a new Navigation-based Application. Put the following code into RootViewController.m:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 5;
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }

    NSLog(@"cell.contentView.bounds.size.width %1.0f",cell.contentView.bounds.size.width);
    // Configure the cell.
    return cell;
}

There are only two changes in the default code required to make this happen: changing the number of rows in the section ("return 5") and the style of the cell must be UITableViewCellStyleSubtitle. Then, when you run the program, you'll see five lines of this:

2011-06-18 11:10:19.976 TestTableCells[7569:207] cell.contentView.bounds.size.width 302
2011-06-18 11:10:19.978 TestTableCells[7569:207] cell.contentView.bounds.size.width 302
2011-06-18 11:10:19.979 TestTableCells[7569:207] cell.contentView.bounds.size.width 302
2011-06-18 11:10:19.980 TestTableCells[7569:207] cell.contentView.bounds.size.width 302
2011-06-18 11:10:19.982 TestTableCells[7569:207] cell.contentView.bounds.size.width 302

Drag some cells off the screen (drag up--down doesn't do anything) and when they reappear, you get this:

2011-06-18 11:10:24.013 TestTableCells[7569:207] cell.contentView.bounds.size.width 320
2011-06-18 11:10:24.047 TestTableCells[7569:207] cell.contentView.bounds.size.width 320
2011-06-18 11:10:24.130 TestTableCells[7569:207] cell.contentView.bounds.size.width 320

Frankly, I'm frustrated as heck with this, and am so very tempted to pony up the $99 (without a working app, even) so I can have somebody at Apple weigh in on this one.

Anybody got any ideas what's going on here?

Thanks!


Wanna' see something more interesting? Try this in place of the static NSString... line:

    NSString *CellIdentifier = [NSString stringWithFormat: @"%d", arc4random() ];

    NSLog(@"%@",CellIdentifier);

Now, every time, the width in the log is always 302. It would seem, then, that a reused cell has different content width than the original cell.

Again... wondering... anybody got a clue?

like image 628
BillEccles Avatar asked Jun 07 '11 21:06

BillEccles


Video Answer


1 Answers

I suspect that what you are seeing is due to changing the cell's accessory view which will eventually resize the content view the next time the cell performs -layoutSubviews. That should occur when the cell is added to the table but until then the bounds of the content view will not be updated.

Regardless I don't see why this would be an issue. You appear to only be concerned with setting the width of your theAgeTextField so if you size it appropriately relative to the content view's current width and set its autoresizingMask flags to give it a flexible width then it should grow or shrink as needed when the bounds of the content view change.

If you need more detailed layout behavior then this should probably all occur within a UITableViewCell subclass. See -prepareForReuse and -layoutSubviews for opportunities to customize the cell and its subviews. Your datasource should be able to just pass theAge to an instance of your cell subclass and not be concerned with the details of how that will be displayed.

like image 160
Jonah Avatar answered Nov 15 '22 23:11

Jonah