Расширяющиеся ячейки табличного представления исчезают
У меня есть ячейки, которые расширяются путем изменения их высоты с помощью вызова метода 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, как показано ниже:
7 ответов
Я не вижу различий в поведении между iOS 5.0 и 4.3.2 в симуляторе или 5.0 в моем телефоне - ячейки исчезают одинаково на каждом. (Я бы проверил 4.2.1 на моем старом iPod touch, но Xcode 4 не может. Грр..) Похоже, что есть простой обходной путь: если вы сделаете оба reloadRowsAtIndexPaths:withRowAnimation: после расширения / сворачивания ваших ячеек и затем вызов reloadData после этого, кажется, чтобы сохранить анимацию.
Вот небольшой демонстрационный проект для этого. Трудно сказать, какова была настоящая проблема - это просто какой-то странный побочный эффект от того, как UIKit выполняет анимацию ячейки. Если вы создаете подкласс [UITableViewCell setAlpha:], вы можете видеть, что табличное представление устанавливает альфа ячейки в 0 и оставляет его там. Weird.
Редактировать: Ну, это странно. Это не работало некоторое время (занималось старым поведением, с исчезновением клеток), но теперь это снова правильно. Может быть, я работал не ту версию. В любом случае, дайте мне знать, если это работает для вас.
Я была такая же проблема. Я подтверждаю, что без перезагрузки строки анимация работает нормально.
Но оказывается, что проблема вызвана возвращением кэшированного UITableViewCell в cellForRowAtIndexPath, когда на самом деле нужен свежий.
Документ для reloadRowsAtIndexPaths:withRowAnimation: говорит: "Перезагрузка строки заставляет табличное представление запрашивать у своего источника данных новую ячейку для этой строки".
Ваш метод cellForRowAtIndexPath возвращает локально кэшированные ячейки. Возвращение новой ячейки решило проблему в моем случае, и никаких обходных путей не потребовалось...
@Javy,
Спасибо за ваш вопрос. Я разрабатывал таблицу с похожим поведением: есть текстовые представления (UITextView
) в моей таблице просмотра ячеек (UITableViewCell
) которые:
- расширение, если для отображения текста без прокрутки требуется новая строка, или
- рушится, если новая строка была удалена
Итак, я нашел ту же проблему. В iOS 5.x, когда я начинал печатать текст, он внезапно становился невидимым. Но в iOS 4.x все отлично работает.
Я нашел решение, и оно хорошо работает для меня.
Решение: просто попробуйте заменить ваш тип анимации UITableViewRowAnimationAutomatic
с UITableViewRowAnimationNone
при перезагрузке конкретной ячейки.
Некоторый дополнительный код: перезагрузите обе ячейки в один момент:
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];
Надеюсь, это поможет вам.
В:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Вы должны вернуть новую клетку. Если ячейка не нужна для создания новой, вам нужно только:
[tableView beginUpdates];
[tableView endUpdates];
Нет необходимости звонить reloadRowsAtIndexPaths
,
Вы могли бы попытаться перезагрузить представление таблицы, когда анимация завершена? в тот момент, если ваша анимация запускается, а затем вы звоните [tableView reloadData]
анимация не будет завершена, поэтому кадр и т. д. могут быть не синхронизированы
Вы можете изменить свой расширенный метод set, чтобы он брал флаг, а также блок завершения анимации, который мог бы содержать код перезагрузки
[cell setExpanded:YES completion:^
//reload code
}];
Мне кажется, что клетка не перерисована должным образом.
Вы пробовали что-то вроде:
[cell.backgroundView setNeedsDisplay]
Хорошо...
до тебя
previousIndexPath_ = indexPath;
и после того, как вы сделаете все расширение / сжатие высот и т.д.; вам нужно сделать что-то вроде
[cellArray replaceObjectAtIndex:previousIndexPath_ withObject:previousCell];
[cellArray replaceObjectAtIndex:indexPath withObject:cell];
что означает, что ваш cellArray должен быть
NSMutableArray* cellArray;