2014-11-21 316 views
16

Stack Overflow上有很多關於UITableViewCell高度動畫的類似問題,但是對於新的iOS8自動佈局驅動的表格視圖沒有任何作用。我的問題:如何使用自動佈局來設置UITableViewCell高度的動畫效果?

自定義單元格:

@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高度。

問題:

爲什麼會發生這種情況?我希望看到我的手機能夠順暢地擴展自動layot的魔力。

注:
我dont't要使用-tableView:heightForRowAtIndexPath:。這是自動佈局時代,對吧?

+0

您仍然需要使用'tableView:heightForRowAtIndexPath:'。這不是自動佈局工作。 – Astoria 2014-11-21 14:30:26

+0

@Astoria,看起來非常像自動佈局工作。 – orkenstein 2015-02-13 22:36:46

+0

@orkenstein我完全同意,現在應該使用自動佈局來完成。我正在嘗試做基本相同的事情:在單元格的contentView上設置約束,並告訴表視圖來爲高度設置動畫。但是,我目前無法實現它的功能。你找到了解決這個問題的方法嗎? – Alex 2015-02-13 23:32:24

回答

38

以下爲我工作:

準備:

  1. viewDidLoad告訴表格視圖中使用自調整大小的細胞:

    tableView.rowHeight = UITableViewAutomaticDimension; 
    tableView.estimatedRowHeight = 44; // Some average height of your cells 
    
  2. 添加約束你通常會,但將它們添加到單元格的contentView

動畫高度變化:

假如你改變了一個約束的constant

myConstraint.constant = newValue; 

...或者你添加/刪除約束。

要動畫這種變化,進行如下操作:

  1. 告訴內容查看動畫的變化:

    [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]; 
    

第一步的持續時間是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 &純自動佈局 - 真正的未來的方式)。

+0

在非動畫版本中:不會在表視圖上調用'reloadRowsAtIndexPaths:withRowAnimation:'with'UITableViewRowAnimationNone'工作?而不是在'UIView'和'beginUpdates' /'endUpdates'上禁用動畫。 – 2015-02-14 16:22:27

+0

@MichałCiuba我不記得確切地嘗試過,但我確實記得想:「似乎reloadRowsAtIndexPaths:withRowAnimation:'沒有重新加載單元格高度,我想我還得嘗試其他的東西」(它可能會已經爲動畫的高度,但不是一個即時更新)。 – Alex 2015-02-14 16:36:41

+1

是的,我的意思是:首先調用'layoutIfNeeded'來更新單元格的高度,然後'reloadRowsAtIndexPaths:withRowAnimation:'來更新表格視圖。 – 2015-02-14 16:38:59

1

我想補充幾點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 
相關問題