2010-09-12 46 views
13

我有一個UIView與一堆子視圖,所有定位使用layoutSubviews。當view被調整大小時,相對位置全部改變。我希望這些重新計算在動畫調整大小時發生(使用+ [UIView beginAnimations:]調用)。這似乎沒有發生。有任何想法嗎?layoutSubviews在動畫中?

回答

23

假設:您想要有多個動畫步驟(即位置不隨幀大小線性變化)。

這對於單個「標準」UIView動畫是不可能的。爲什麼?幀/邊界只設置一次。

Core Animation有三個 「層樹」:

  • 模型樹是你的應用認爲東西。
  • 演示樹大約是屏幕上顯示的內容。
  • 渲染樹大約是Core Animation合成的內容。

UIView是一個圍繞模型層(稍薄)的包裝。在UIView動畫期間,Core Animation更新演示/渲染樹—模型樹表示動畫的端點。結果是您的代碼可以(大部分)將動畫視爲瞬間—將視圖從A移動到B會立即將其移動到B;這種變化恰好給用戶帶來了生氣。

直接使用CALayer/CAAnimation可以做更復雜的事情,但我沒有調查太多。

您可以使用 - [UIView setAnimationDidStopSelector:]將多個動畫鏈接在一起。 (您也可以嘗試使用多個動畫與setAnimationDelay一起:,但我不知道對同一屬性的多個動畫會發生什麼情況,你可能有運氣setAnimationBeginsFromCurrentState :.)

如果你想真正的細粒度控制,CADisplayLink(OS 3.1+)是每次刷新屏幕後都會觸發的計時器。回退選項(支持3.0)是在30/60 Hz左右使用NSTimer。

+0

感謝在幕後的詳細研究。雖然我在外圍意識到樹的層次結構,但綜合來看,爲什麼Core Animation的架構基本上不允許我想要做的事情。 – 2010-09-12 13:36:53

4

過帳完整性。感謝tc。爲了解釋我所要做的事情,Core Animation不支持。

我終於想出了一個合理的解決方案。而是在-layoutSubviews中佈置我的子視圖,我在-setBounds:中這樣做。然後,當我在UIView + beginAnimations:block中包裝一個-setBounds:調用時,那些定位調用也會動畫化,最終的結果就是一切正確地動畫到上帝的位置。

+1

哦......如果是這樣的話,那麼我誤解你在說什麼。試試'view.frame = blah; [view layoutIfNeeded]' – 2010-09-13 00:37:36

+0

不,這隻會將它們移動到位,然後爲邊界設置動畫。這是我最初嘗試的。 – 2010-09-13 01:08:58

+1

我想實現類似的東西,但是我的setBounds只能調用一次(與最後的邊界),所以我的子視圖在動畫過程中不會重新對齊。有什麼我錯過了嗎? – alexleutgoeb 2011-10-11 15:08:20

13

我知道這是一個古老的問題,但是這個代碼對我很有效(適合你的改變框架的例子)。

-(void)layoutSubviews{ 
    [super layoutSubviews]; 
    // layout your subviews here, or whatever 
} 

-(void)someMethod{ 
    double duration=...; 
    [UIView animateWithDuration:duration animations:^{ 
     self.frame = ...; 
     [self layoutIfNeeded]; 
    }]; 
} 

當然,您可以從另一個對象調用此方法。 「技巧」是調用layoutIfNeeded(或layoutSubviews直接 - 同樣的事情,如果你改變框架setNeedsLayout被稱爲)。

作爲tc。很好地解釋了「圖層樹」,您只需強制表示層以動畫顯示模型圖層的最後階段。

該方法的優點是可以控制幀/邊界更改何時生效以及何時更新。

希望這可以幫助別人:)。

+0

這非常有幫助!在我閱讀你的答案之前,我從未理解Core Animation的這部分內容。 – 2013-01-13 18:33:30

+0

@JohnWright:我的榮幸:) – JakubKnejzlik 2013-01-15 13:48:21

+1

可能需要在layoutIfNeeded之前調用setNeedsLayout。 – Karmeye 2013-12-15 16:30:05

11

完成@ GrizzlyNetch的前面回答,您可以設置UIViewAnimationOptionLayoutSubviews動畫選項,這樣你就不需要調用layoutIfNeeded

-(void)someMethod{ 
    double duration = ...; 
    [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionLayoutSubviews animations:^{ 
     self.frame = ...; 
    } completion:nil]; 
}