Изменения UITableView cell.contentView.bounds.size.width при повторном использовании ячеек

Я использую cell.contentView.bounds.size.width для вычисления положения текстового поля в ячейке UITableView. Когда ячейка создана, отладочный код сообщает ширину как 302. Когда ячейка прокручивается с экрана, а затем возвращается, код отладки сообщает, что он равен 280 - каждый раз. Кажется, он не хочет возвращаться к 302 и остается застрявшим до 280. Конечным результатом является то, что текстовое поле попадает не в то место во второй раз, когда поле помещается в содержимое cellView, хотя оно помещено в правое место в первый раз.

Я цифра 22 как-то значительна, но я не знаю, что это такое. Угадав, что это может быть стрелка раскрытия, я переместил код "очистить ячейку" перед определением ширины, включая установку аксессуара на наду.

Кто-нибудь может сказать мне, что здесь происходит?

Код (с нерелевантным - что я знаю - вырезанный материал) выглядит следующим образом:

// 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;
}

Хотите попробовать это дома, мальчики и девочки?

Начните с нового навигационного приложения. Поместите следующий код в 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;
}

Для кода этого кода требуется всего два изменения кода: изменение количества строк в разделе ( "возврат 5" ), а стиль ячейки должен быть UITableViewCellStyleSubtitle. Затем, когда вы запустите программу, вы увидите пять строк этого:

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

Перетащите некоторые ячейки с экрана (перетащить вверх - ничего не делает), и когда они снова появятся, вы получите следующее:

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

Честно говоря, я расстроен, как черт с этим, и мне так очень хочется поднять $99 (без рабочего приложения, даже), поэтому я могу заставить кого-то в Apple взвесить на этом.

У кого-нибудь есть идеи, что здесь происходит?

Спасибо!


Хотите увидеть что-то более интересное? Попробуйте это вместо строки static NSString...:

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

    NSLog(@"%@",CellIdentifier);

Теперь каждый раз ширина в журнале всегда равна 302. Казалось бы, что повторно используемая ячейка имеет разную ширину содержимого, чем исходная ячейка.

Опять... интересно... кто-нибудь понял?

Ответы

Ответ 1

Я подозреваю, что то, что вы видите, связано с изменением вида сотового аксессуара, который в конечном итоге изменит размер представления содержимого в следующий раз, когда ячейка выполнит -layoutSubviews. Это должно произойти, когда ячейка добавляется в таблицу, но до тех пор границы представления содержимого не будут обновляться.

Несмотря на это, я не понимаю, почему это было проблемой. Кажется, что вы занимаетесь только настройкой ширины вашего theAgeTextField, поэтому, если вы соответствующим образом определяете ее по отношению к текущей ширине представления содержимого и устанавливаете ее флаги autoresizingMask, чтобы дать ей гибкую ширину, тогда она должна расти или уменьшаться по мере необходимости, когда границы представления содержимого меняются.

Если вам требуется более подробное поведение макета, это, вероятно, должно произойти в подклассе UITableViewCell. См. -prepareForReuse и -layoutSubviews для возможности настройки ячейки и ее подзонов. Ваш источник данных должен иметь возможность просто передать theAge в экземпляр вашего подкласса ячейки и не учитывать детали того, как это будет отображаться.

Ответ 2

Я столкнулся с тем же, за исключением того, что смещение было 20 вместо 22. Я думаю, что ответ Джона на правильном пути, но для быстрого обходного пути, который позволяет избежать изменения размера cell.contentView.frame/bounds, я просто использовал cell.frame/bounds как моя ссылка для выделения представлений в содержимом cellView.

Ответ 3

Вы должны реализовать высоту для метода делегата строки и выполнить все ваши вычисления там

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

// do math

return newheight;
}

Это даст вам то, что вам нужно, у вас также есть доступ к указательному пути, поэтому вы можете легко найти строку в своем массиве и сделать все, что вам нужно, иначе вы получите размер повторно используемой строки из очереди, который всегда является размером строки по умолчанию.