Расширяющиеся ячейки табличного представления исчезают

17

У меня есть ячейки, которые расширяются путем изменения их высоты с помощью вызова метода setExpanded:

.

Затем я вызываю reloadRowsAtIndexPaths: чтобы обновить ячейки.

Проблема в том, что клетки просто исчезают и появляются снова случайно. Я подозреваю, что это связано с тем, как работает индексация.

Если я вызываю reloadData или beginUpdates / endUpdates, ячейки работают как положено, но я теряю анимацию.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    JVCell *cell = (JVCell*)[tableView cellForRowAtIndexPath:indexPath];
    JVCell *previousCell = nil;

    if( previousIndexPath_ != nil ) // set to nil in viewDidLoad
    {
        previousCell = (JVCell*)[tableView cellForRowAtIndexPath:previousIndexPath_];
    }


    // expand or collapse cell if it's the same one as last time
    if( previousCell != nil && [previousIndexPath_ compare:indexPath] == NSOrderedSame && [previousCell expandable] )
    {
        [previousCell setExpanded:![cell expanded]];
        NSArray *indexPathArray = [NSArray arrayWithObject:previousIndexPath_];
        [tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationAutomatic];
    }
    else
    {
        // collapse previous cell
        if( previousCell != nil && [previousCell expandable] )
        {
            if( [previousCell expanded] ) [previousCell setExpanded:NO];
            NSArray *indexPathArray = [NSArray arrayWithObject:previousIndexPath_];
            [tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationAutomatic];
        }

        // expand new cell
        if( [cell expandable] )
        {
            [cell setExpanded:YES];
            NSArray *indexPathArray = [NSArray arrayWithObject:indexPath];
            [tableView reloadRowsAtIndexPaths:indexPathArray withRowAnimation:UITableViewRowAnimationAutomatic];
        }
    }

    previousIndexPath_ = indexPath;

    // works as expected, but I lose the animations
    //[tableView reloadData];

    // works as expected, but I lose the animations
    //[tableView beginUpdates];
    //[tableView endUpdates];
}

РЕДАКТИРОВАТЬ: обновлено и теперь включает методы cellForRowAtIndexPath и heightForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSUInteger section = [indexPath section];
    NSUInteger row = [indexPath row];
    JVCellSectionData *sectionData = [sections_ objectAtIndex:section]; // NSArray of SectionData objects
    NSArray *cellArray = [sectionData cells]; // NSArray of cells
    UITableViewCell *cell = [cellArray objectAtIndex:row];
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    NSUInteger section = [indexPath section];
    NSUInteger row = [indexPath row];
    JVCellSectionData *sectionData = [sections_ objectAtIndex:section];
    NSArray *cellArray = [sectionData cells];
    JVCell *cell = [cellArray objectAtIndex:row];
    return [cell cellHeight]; // changed when selected with setExpanded: method
}

Изменить 2 . Я сделал QuickTime видео о происходящем и снял снимки экрана.

Я пытаюсь расширить ячейку, а не заменять, вставлять или удалять ячейки. Каждая ячейка имеет одно или несколько подпредставлений. Высота ячейки изменяется в зависимости от того, «расширена» она или нет. К представлению содержимого добавлены подпредставления, и его свойство clipToBounds имеет значение YES. Когда ячейки расширяются или сворачиваются, значение высоты изменяется вместе с рамкой ячейки (включая вид фона и выбранный вид фона). Я зарегистрировал все значения кадра до, во время и после расширения, и все они соответствуют их состоянию и положению.

Имейте в виду, что это нормально работает на iOS 4.3, как показано ниже:

    
задан TigerCoding 22.02.2012 в 14:46
источник
  • Такое поведение, вероятно, связано с тем, что, хотя вы изменяете изменения в ячейке, вы не обязательно меняли источник данных, чтобы отражать изменения. Поэтому, когда происходит перезагрузка, ячейки воссоздаются, поскольку они были первоначально (изменения, кажется, исчезают) –  Damo 22.02.2012 в 14:54
  • Я меняю высоту и визуальный внешний вид в методе setExpanded:. В этом методе я пересчитываю высоту, а затем устанавливаю фрейм ячейки (и подпункты) по мере необходимости. Есть ли что-то еще, что я могу сделать? –  TigerCoding 22.02.2012 в 14:57
  • Что нужно проверить 1. cellForRowAtIndexPath: method & 2. calls to reloadData. То, что я имел в виду под моим первоначальным комментарием, было: если cellForRowAtIndexPath: вызывается после вашей анимации, будут ли ячейки созданы a) как они были или b), как вы хотите, чтобы они были? то есть, если данные, которые используются для создания ячеек в первую очередь, не меняются, то при перезагрузке любые анимированные изменения, которые вы сделали, будут «исчезать». –  Damo 22.02.2012 в 16:17
  • Почему вы не используете метод делегата: - (CGFloat) tableView: (UITableView *) tableView heightForRowAtIndexPath: (NSIndexPath *) indexPath? –  onnoweb 22.02.2012 в 16:35
  • @ Damo Я предварительно создаю все ячейки в viewDidLoad. Они не созданы и не используются в cellForRowAtIndexPath. Единственное, что меняется, это высота. Каждая ячейка имеет один или несколько под-представлений, которые обрезаются в зависимости от высоты ячейки. Интересно, что при нажатии на ячейки, которые не расширяют ведение журнала, всегда отображаются правильные номера разделов / строк, но в тот момент, когда я нажимаю расширяющуюся ячейку, а затем нажмите другую ячейку, номер раздела неверен. –  TigerCoding 22.02.2012 в 17:58
Показать остальные комментарии

7 ответов

7

Я не вижу различий в поведении между iOS 5.0 и 4.3.2 в симуляторе или 5.0 в моем телефоне - ячейки исчезают одинаково на каждом. (Я бы проверил 4.2.1 на моем старом iPod touch, но Xcode 4 не может. Грр ..) Похоже, что есть простой обходной путь: если вы сделаете оба reloadRowsAtIndexPaths: withRowAnimation: после расширения / сворачивания ваших ячеек и затем вызов reloadData после этого, кажется, чтобы сохранить анимацию.

Вот небольшой демонстрационный проект для этого. Трудно сказать, какова была настоящая проблема - это просто какой-то странный побочный эффект от того, как UIKit выполняет анимацию ячейки. Если вы создаете подкласс [UITableViewCell setAlpha:], вы можете видеть, что табличное представление устанавливает альфа ячейки в 0 и оставляет его там. Weird.

Редактировать: Ну, это странно. Это не работало некоторое время (занимался старым поведением, с исчезновением клеток), но теперь это снова правильно. Может быть, я работал не ту версию. В любом случае, дайте мне знать, если это работает для вас.

    
ответ дан davehayden 27.02.2012 в 23:35
  • Данные перезагрузки работают, но анимация, к сожалению, похожа на фанки. Однако, если я переопределяю метод setAlpha, как вы предложили, и не позволяйте ему устанавливать альфа, проблема, похоже, исчезнет. Я не могу представить, почему клетки будут исчезать. –  TigerCoding 28.02.2012 в 12:40
  • Кажется, что-то происходит. Вызов reloadData или вызов beginUpdates и endUpdates, похоже, работает нормально для меня, как и в этом сообщении SO. Используете ли вы какие-либо другие методы делегатов UITableView, чтобы изменить способ отображения вещей? Ваш код не работает, как демонстрационная версия, которую я опубликовал выше, и если да, можете ли вы выяснить, где она расходится в коде? Если образец работает, попробуйте объединить свой код в понемногу, чтобы узнать, что заставляет его действовать по-другому. –  davehayden 28.02.2012 в 21:05
  • Я проверил ваш код, и он работает, как вы сказали. У вас была проблема с вашим кодом раньше? Вы сказали: «Ну, это странно. Это немного не работало ...» Это всегда будет терпеть неудачу для меня, если я не переоцениваю альфу. Я следил за потоком в отладчике, и он перешел от «reloadRowsAtIndexPaths: withAnimation:» к методу частного табличного представления (обновление, которое я думаю), а затем прямо к setAlpha, поэтому он не вызывает никаких других методов делегата. Я попытаюсь удалить часть содержимого из моего подкласса ячеек (это довольно сложно), чтобы определить виновника. –  TigerCoding 29.02.2012 в 13:14
  • Странный бит был только тем, что он работал, а затем внезапно это не было, и тогда это было снова. Но я думаю, что просто потерял контроль над тем, что я ткнул. :) –  davehayden 02.03.2012 в 05:31
  • Любая вероятность добавить 3 изображения в виде подзонов к ячейкам, один поверх другого по высоте, и чтобы ячейка расширялась, открывала или скрывала изображения, как это происходит? Я думаю, что с простым текстом он работает, но когда используется изображение, это может вызвать проблемы. Я назначаю растяжимые изображения как для backgroundView, так и для selectedBackgroundview (путем установки их в виде изображения при их создании). –  TigerCoding 03.03.2012 в 14:51
Показать остальные комментарии
5

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

Но оказывается, что проблема вызвана возвратом кэшированного UITableViewCell в cellForRowAtIndexPath, когда на самом деле нужен свежий.

Документ для reloadRowsAtIndexPaths: withRowAnimation: говорит: «При перезагрузке строки табличное представление запрашивает у своего источника данных новую ячейку для этой строки».

Ваш метод cellForRowAtIndexPath возвращает локально кэшированные ячейки. Возвращение новой ячейки решило проблему в моем случае, и никаких обходных путей не требовалось ...

    
ответ дан Dan Mardale 12.11.2012 в 16:49
2

@Javy,

Спасибо за ваш вопрос. Я разрабатывал таблицу с похожим поведением: в моих ячейках табличного представления ( UITextView ) есть текстовые представления:

  1. расширение, если для отображения текста без прокрутки требуется новая строка, или
  2. рушится, если новая строка была удалена

Итак, я обнаружил ту же проблему. В iOS 5.x , когда я начинал печатать текст, он внезапно становился невидимым. Но в iOS 4.x все работает нормально.

Я нашел решение, и оно хорошо работает для меня.

Решение . Просто попробуйте заменить тип анимации UITableViewCell на UITableViewRowAnimationAutomatic при перезагрузке конкретной ячейки.

Дополнительный код: перезагрузите обе ячейки за один раз:

    NSMutableArray *indexes = [NSMutableArray arrayWithCapacity:2];
    // collapse previous cell
    if( previousCell != nil && [previousCell expandable] )
    {
        if( [previousCell expanded] ) [previousCell setExpanded:NO];
        [indexes addObject:previousIndexPath_];
    }

    // expand new cell
    if( [cell expandable] )
    {
        [cell setExpanded:YES];
        [indexes addObject:indexPath];
    }

    [tableView reloadRowsAtIndexPaths:indexes withRowAnimation:UITableViewRowAnimationNone];

Надеюсь, это поможет вам.

    
ответ дан Nekto 01.03.2012 в 13:49
  • изменение этого параметра не позволяет ячейке исчезнуть, когда она расширяется, но она все еще исчезает, когда она обрушивается. :( –  TigerCoding 01.03.2012 в 14:31
  • @Javy, пожалуйста, см. мой ответ на вопрос. Попробуйте перезагрузить ячейку, которую вы хотите свернуть и развернуть, используя один вызов reloadRowsAtIndexPaths. Просто сохраните все соответствующие индексированные в одном массиве и передайте массив этому методу (см. Мой ответ). –  Nekto 01.03.2012 в 15:37
  • Я надеялся на это, так как альфа не изменилась при расширении, но я попробовал вышеуказанный код, и вместо этого у ячеек есть отсечки от них, когда они рушится. Кажется, что это происходит только в том же разделе, в котором находятся ячейки. Что более странно, даже если я переопределяю альфу и не даю ей нуля, она все же отключает нижнюю часть (или верхнюю часть) ячейки. Это похоже на то, что он не смотрит на новый размер ячейки. –  TigerCoding 02.03.2012 в 17:53
  • И что происходит, если вы увеличите высоту расширяемых строк? Я не понимаю, что теперь не так. –  Nekto 02.03.2012 в 21:42
  • Может быть, вы можете попытаться перезагрузить разделы (разделы)? У них тоже будут анимации –  Nekto 02.03.2012 в 21:45
Показать остальные комментарии
0

Мне кажется, что ячейка перерисована неправильно.

Вы пробовали что-то вроде:

[cell.backgroundView setNeedsDisplay]
    
ответ дан Yedy 01.03.2012 в 12:09
  • Да, я поместил это в конец layoutSubViews. Я начинаю думать, что это ошибка iOS 5, так как она отлично работает, это iOS 4. –  TigerCoding 01.03.2012 в 14:32
  • Хм, может быть проблема с синхронизацией. Не могли бы вы попробовать верхний код в cellForRowAtIndexPath? –  Yedy 01.03.2012 в 17:31
  • Но вся ячейка исчезает. Кажется странным назвать этот метод там. Зачем обновлять backgroundView? Возможно, что-то еще? –  TigerCoding 01.03.2012 в 18:21
  • cell setNeedsLayout? Всегда ли это, что расширенные строки сначала появляются и исчезают? –  Yedy 01.03.2012 в 18:53
  • Строка расширяется и исчезает одновременно. затухание начинается сразу, когда начинается расширение, как будто это часть анимации. –  TigerCoding 02.03.2012 в 17:54
0

Вы можете попробовать перезагрузить табличное представление после завершения анимации? в данный момент, если ваша анимация запускается, а затем вы вызываете [tableView reloadData] , анимация не будет завершена, поэтому кадр и т. д. могут выйти из синхронизации

вы можете изменить свой расширенный метод set для принятия флага, а также блока завершения анимации, который может содержать код перезагрузки

[cell setExpanded:YES completion:^
    //reload code
}];
    
ответ дан wattson12 01.03.2012 в 13:16
  • Оно все равно исчезнет до тех пор, пока не будет вызвана перезагрузка? Как упоминалось в @Yedi в другом ответе, я думаю, что это ошибка iOS 5, потому что для этого нет разумного объяснения. Только обходные пути, чтобы избежать этого. –  TigerCoding 01.03.2012 в 14:34
0

В:

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

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

[tableView beginUpdates];
[tableView endUpdates];

Нет необходимости вызывать reloadRowsAtIndexPaths .

    
ответ дан gaoyp 10.04.2012 в 09:52
  • Спасибо, Раджеш, но виновник был разрешен в этом вопросе, который я опубликовал позже. stackoverflow.com/questions/9649491/... –  TigerCoding 14.04.2012 в 09:01
-1

Хорошо ...

перед вами

previousIndexPath_ = indexPath;

и после того, как вы сделаете все расширение / сжатие высот и т.д .; вам нужно сделать что-то вроде

[cellArray replaceObjectAtIndex:previousIndexPath_ withObject:previousCell];
[cellArray replaceObjectAtIndex:indexPath withObject:cell];

это означает, что ваш cellArray должен быть

NSMutableArray* cellArray;
    
ответ дан Damo 23.02.2012 в 09:29
  • Почему массив ячеек должен быть изменен? Ячейки не добавляются. удалены или переупорядочены каким-либо образом. Я думаю, может быть, я не объяснил, что происходит достаточно хорошо? См. Мои правки выше. –  TigerCoding 23.02.2012 в 12:38
  • Mutable, чтобы вы могли заменить объекты ячейки, как указано выше. - вам нужно обновить cellArray, а также обновить текущую ячейку в представлении, потому что данные перезагрузки смотрят только на массив ячеек. Код, который у вас есть в didSelectRowAtIndexPath, принимает ячейку из самого представления таблицы. но вам нужно также изменить массив ячеек, потому что в противном случае вы получите поведение, которое видите. –  Damo 23.02.2012 в 14:41
  • Я благодарен за вашу помощь, но то, что вы сказали, не имеет для меня большого смысла. У меня есть массив объектов «SectionData», которые содержат две строки (текст заголовка и нижнего колонтитула) и неизменяемый массив ячеек. Ячейки никогда не меняют положение. Изменяется только высота ячейки. Даже в этом примере кода roostersoftstudios.com/2011/04/14/... автор вызывает перезагрузку и не вызывает замену ни на одной из ячеек. –  TigerCoding 23.02.2012 в 15:24
  • вы уже пытались добавить эти несколько строк? Если это не работает, что вы потеряли? –  Damo 23.02.2012 в 15:31
  • Следуя вашим советам, изменил массивы, подлежащие изменчивости, внедрил ваш код, и я вижу, что он меняет позиции ячеек в представлении таблицы. Тем не менее, первоначальный щелчок по расширяющемуся представлению таблицы не нужно менять, но он все еще исчезает. –  TigerCoding 23.02.2012 в 15:50