Пользовательский UITableViewCell с автоматическим макетом и вспомогательным видом

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

Как видите, ячейка занимает примерно 1,5 экрана:

введите здесь описание изображения

Однако, если я поверну устройство и поверну обратно, оно выглядит нормально:

введите здесь описание изображения

Как видите, ничего сложного я не сделал:

введите здесь описание изображения

У меня есть очень НЕ ИДЕАЛЬНЫЙ обходной путь, который нужно сделать:

-(void)viewDidAppear:(BOOL)animated 
{
    [super viewDidAppear:animated];
    [self.tableView reloadData];
}

Но это, очевидно, вызывает «вспышку», когда вы впервые видите экран. В более сложном сценарии вспышка гораздо более очевидна.

У меня есть другой обходной путь, но это вызывает исключение автоматического макета:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
    BasicCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BasicCell" forIndexPath:indexPath];
    cell.basicLabel.text = @"Hello this is just some text that should get the label to go over multiple lines";
    [cell.basicLabel layoutIfNeeded];
    return cell;
}

Исключение:

введите здесь описание изображения

По крайней мере, этот метод не дает мне мигать пользовательский интерфейс.

Если я удалю дополнительный вид, он действительно работает отлично.

ОБНОВЛЕНИЕ: я добавил образец проекта в github: https://github.com/fwaddle/TableCellAccessoryTest

ОБНОВЛЕНИЕ № 2: Оказывается, еще один способ обойти эту ошибку — разместить ячейку в коде. Я только что попытался сделать то же самое в коде, и он не выдал предупреждение и работал нормально. Похоже на баг ИБ.

Любые идеи, как обойти эту проблему? Спасибо.


comment
Правильно установите ограничения внутри своей ячейки, что иногда может быть сложно, а затем установите для свойства rowHeight в табличном представлении значение UITableViewAutomaticDimension. Также это не исключение, это предупреждение о неправильной настройке. Неперехваченное исключение завершит ваше приложение.   -  person Michael    schedule 08.05.2015
comment
Привет @Nikita, ограничения установлены правильно, и я правильно установил rowHeight: - (void)viewDidLoad { [super viewDidLoad]; self.tableView.rowHeight = UITableViewAutomaticDimension; self.tableView.estimatedRowHeight = 45; } Но я понимаю ваше мнение о том, что это не исключение.   -  person Mof    schedule 08.05.2015
comment
Я думаю, что это проблема с вашими ограничениями. Очистите свою сборку и удалите ограничения, которые не используются в макете, затем соберите и запустите ее.   -  person Michael    schedule 08.05.2015
comment
Есть только 4 ограничения, чтобы приклеить этикетку со всех 4 сторон. Я не вижу необязательных ограничений. На приведенном выше снимке экрана вы можете увидеть 4 ограничения.   -  person Mof    schedule 08.05.2015
comment
Попробуйте увеличить estimatedRowHeight, у меня была эта проблема, и когда я увеличил это значение, все сработало отлично.   -  person Michael    schedule 08.05.2015
comment
Увеличение estimatedRowheight не дало эффекта. Я загрузил пример проекта на github и обновил приведенную выше ссылку.   -  person Mof    schedule 08.05.2015
comment
Вы должны подать отчет об ошибке в Apple. Добавление индикатора раскрытия, безусловно, не должно нарушать самоопределение размера ячеек.   -  person rdelmar    schedule 08.05.2015
comment
Привет @rdelmar Я только что отправил отчет об ошибке в Apple. Я согласен, что это определенно выглядит как ошибка в iOS. Спасибо.   -  person Mof    schedule 08.05.2015


Ответы (2)


Реализуйте следующий метод делегата, так как это решило проблему для меня.

- (void)tableView:(UITableView *)tableView   
willDisplayCell:(UITableViewCell *)cell 
forRowAtIndexPath:(NSIndexPath*)indexPath

Табличное представление отправляет это сообщение своему делегату непосредственно перед тем, как использовать ячейку для рисования строки, тем самым позволяя делегату настроить объект ячейки до его отображения. Этот метод дает делегату возможность переопределить свойства на основе состояния, установленные ранее табличным представлением, такие как выделение и цвет фона. После возврата делегата табличное представление устанавливает только свойства альфа-канала и фрейма, а затем только при анимации строк, когда они скользят внутрь или наружу.

Добавьте этот код в свой tableViewController:

 - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell   forRowAtIndexPath:(NSIndexPath *)indexPath{

    BasicCell *basicCell = (BasicCell *)cell;
    basicCell.basicLabel.text = @"Hello this is just some text that should get the label to go over multiple lines";

}
person Michael    schedule 08.05.2015
comment
Хотя ваше решение на данный момент является лучшим решением, оно все же не идеально. Ваше решение по-прежнему создает слишком высокие ячейки. Посмотрите, что происходит, когда вы поворачиваете устройство по часовой стрелке, а затем назад. Вы заметите, что клетки становятся меньше и достигают нужной высоты. Я также подал отчет об ошибке в Apple, так как это похоже на ошибку iOS. - person Mof; 08.05.2015

Поэтому даже создание ограничений в коде иногда не решает эту проблему. Кажется, вам нужно еще несколько изменений. В пользовательской ячейке таблицы добавьте следующее, особенно если вы меняете тип аксессуара в зависимости от содержимого ячейки (например, галочка):

-(void) setAccessoryType:(UITableViewCellAccessoryType)accessoryType {
  [super setAccessoryType:accessoryType];
  [self setNeedsUpdateConstraints];
}

Также удалите ячейку прототипа в раскадровке и вместо этого зарегистрируйте свой класс:

-(void) viewDidLoad {
  [super viewDidLoad];
  [self.tableView registerClass:[MyCustomCell class] forCellReuseIdentifier:@"MyCustomCell"];
}

Иногда я обнаруживаю, что мне все еще нужно заставить метки (особенно многострочные метки) изменить макет в cellForRowAtIndexPath:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
  MyCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyCustomCell" forIndexPath:indexPath];
  cell.customLabel.text = .....
  [cell.customLabel layoutIfNeeded];
  return cell;
}

Все вышеперечисленное исправило мои проблемы, поэтому я надеюсь, что они будут полезны другим, и вы не тратите на это много времени.

Я до сих пор ничего не слышал от Apple об отчете об ошибке, но я полагаю, что это вполне нормально.

person Mof    schedule 06.08.2015