Как оживить высоту UITableViewCell с помощью автоматической компоновки?

Есть много похожих вопросов о переполнении стека о анимации высоты UITableViewCell, но ничего не работает для нового табличного представления iOS8 с автоматической компоновкой. Моя проблема:

Пользовательская ячейка:

@property (weak, nonatomic) IBOutlet iCarousel *carouselView;
@property (weak, nonatomic) IBOutlet UIPageControl *pageControl;
@property (weak, nonatomic) IBOutlet UIButton *seeAllButton;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *carouselHeightConstraint;

Примечание carouselHeightConstraint. Это ограничение по высоте для subview представления контента (единственное подвью).

Высота установлена ​​на 230.0f, например. При первой загрузке это выглядит так: enter image description here

Затем в действии Просмотреть все я хочу развернуть ячейку, мой код:

- (IBAction)seeAllButtonAction:(id)sender {

  BOOL vertical = !self.carouselCell.carouselView.vertical;
  self.carouselCell.carouselView.type = vertical ? iCarouselTypeCylinder : iCarouselTypeLinear;
  self.carouselCell.carouselView.vertical = vertical;

  [UIView transitionWithView:self.carouselCell.carouselView
                    duration:0.2
                     options:0
                  animations:^{

    self.carouselCell.carouselHeightConstraint.constant = vertical ? CGRectGetHeight(self.tableView.frame) : 230;
    [self.carouselCell setNeedsUpdateConstraints];
    [self.carouselCell updateConstraintsIfNeeded];
    [self.tableView beginUpdates];
    [self.tableView endUpdates];

                  completion:^(BOOL finished) {
                  }];
}

Как вы можете видеть, я стараюсь использовать это хорошее старое решение:
Можете ли вы изменить изменение высоты на UITableViewCell при выборе?

И результат:

enter image description here

Моя ячейка сжимается до 44.0f height.

Вопрос:

Почему это происходит? Я ожидаю, что моя камера будет плавно расширяться с помощью магии авто-layot.

Примечание:
Я не хочу использовать -tableView:heightForRowAtIndexPath:. Это авто-макет эры, правильно?

Ответы

Ответ 1

Следующие работали для меня:

Приготовление:

  • В viewDidLoad скажите в представлении таблицы использование ящиков для самостоятельной калибровки:

    tableView.rowHeight = UITableViewAutomaticDimension;
    tableView.estimatedRowHeight = 44; // Some average height of your cells
    
  • Добавьте ограничения, как обычно, но добавьте их в ячейку contentView!

Изменение высоты анимации:

Скажем, вы изменили ограничение constant:

myConstraint.constant = newValue;

... или вы добавляете/удаляете ограничения.

Чтобы оживить это изменение, действуйте следующим образом:

  • Сообщайте contentView о необходимости изменения:

    [UIView animateWithDuration: 0.3 animations: ^{ [cell.contentView layoutIfNeeded] }]; // Or self.contentView if you're doing this from your own cell subclass
    
  • Затем скажите в представлении таблицы реагировать на изменение высоты с помощью анимации

    [tableView beginUpdates];
    [tableView endUpdates];
    

Длительность 0,3 на первом этапе - это то, что, по-видимому, является длительностью, которую UITableView использует для своих анимаций при вызове begin/endUpdates.

Бонус - изменение высоты без анимации и без перезагрузки всей таблицы:

Если вы хотите сделать то же самое, что и выше, но без анимации, сделайте следующее:

[cell.contentView layoutIfNeeded];
[UIView setAnimationsEnabled: FALSE];
[tableView beginUpdates];
[tableView endUpdates];
[UIView setAnimationsEnabled: TRUE];

Резюме:

// Height changing code here:
// ...

if (animate) {
    [UIView animateWithDuration: 0.3 animations: ^{ [cell.contentView layoutIfNeeded]; }];
    [tableView beginUpdates];
    [tableView endUpdates];
}
else {
    [cell.contentView layoutIfNeeded];
    [UIView setAnimationsEnabled: FALSE];
    [tableView beginUpdates];
    [tableView endUpdates];
    [UIView setAnimationsEnabled: TRUE];
}

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

Ответ 2

Я бы хотел добавить несколько слов к ответу на Alex.

Если вы вызываете beginUpdates и endUpdates внутри cellForRowAtIndexPath или willDisplayCell, ваше приложение выйдет из строя. После оживления увеличения вашей ячейки вы можете захотеть, чтобы он остался прежним после прокрутки к таблице TableView. Вы также можете захотеть, чтобы остальные ячейки сохраняли свою высоту одинаково. Но помните, что ячейки многоразовые, поэтому вы можете оказаться в других клетках с повышенной высотой.

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

public func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
...
    myConstraint.constant = itemForCell.value == "x" ? 50 : 20 // stop right here
    cell.layoutIfNeeded() <- don't do this or some of your constraints will break
    beginUpdates() <-- if you do this your app will crash
    endUpdates() <-- same here