如何使用自动布局动画UITableViewCell高度?

时间:2014-11-21 10:00:02

标签: ios objective-c uitableview ios8 autolayout

关于UITableViewCell高度动画的Stack Overflow上有很多类似的问题,但是对于新的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。这是内容视图的子视图(唯一的子视图)的高度约束。

例如,高度设置为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) {
                  }];
}

正如您所看到的,我尝试使用这个很好的旧解决方案:
Can you animate a height change on a UITableViewCell when selected?

结果:

enter image description here

我的单元格缩小44.0f高度。

问题:

为什么会这样?我希望看到我的细胞能够通过自动布局的魔力顺利扩展。

注意:
我不想使用-tableView:heightForRowAtIndexPath:。它的自动布局时代,对吧?

2 个答案:

答案 0 :(得分:43)

以下对我有用:

<强>制备

  1. viewDidLoad上告诉表视图使用自调整单元格:

    tableView.rowHeight = UITableViewAutomaticDimension;
    tableView.estimatedRowHeight = 44; // Some average height of your cells
    
  2. 像往常一样添加约束,但将它们添加到单元格contentView

  3. 动画高度更改:

    假设您更改了约束&#39; s constant

    myConstraint.constant = newValue;
    

    ...或者您添加/删除约束。

    要为此更改设置动画,请按以下步骤操作:

    1. 告诉contentView动画更改:

      [UIView animateWithDuration: 0.3 animations: ^{ [cell.contentView layoutIfNeeded] }]; // Or self.contentView if you're doing this from your own cell subclass
      
    2. 然后告诉表视图使用动画

      对高度变化作出反应
      [tableView beginUpdates];
      [tableView endUpdates];
      
    3. 第一步的持续时间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];
      }
      

      你可以查看我在用户选择它时扩展的单元格的实现here(纯粹的Swift&amp;纯自动布局 - 真正的未来之路)。

答案 1 :(得分:3)

我想在Alex的答案中加上几点。

如果在cellForRowAtIndexPath或willDisplayCell中调用beginUpdates和endUpdates,您的应用程序将崩溃。在为单元格增加动画后,您可能希望在滚动到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