2011-03-07 62 views
0

CAAnimation不提供分配除標準「animationDidStart:」/「animationDidStop:」方法之外的回調函數的機制。替代使用CABasicAnimation回調?

我有一個自定義的UIControl,它使用了2個重疊的CALayers。這種控制的目的類似於一個老式的聲納。頂層的內容包含一個不斷旋轉的圖像(稱之爲「魔杖」)。該層下面是一個「spriteControl」層,當魔杖越過它們時呈現閃爍。

blips表示的對象被spriteControl預取並組織成不可見的CAShapeLayers。我正在使用CABasicAnimation一次旋轉魔杖10度,然後利用「animationDidStop:」方法調用spriteControl上的一個方法,該方法使用魔杖圖層的當前旋轉值(又稱爲標題),並將Alpha設置的動畫設置爲1.0到0.0用於模擬閃爍和淡出效果。最後,這個過程無限期地重新開始。

雖然這種使用CAAnimation回調的方法確保了棒到達「ping」位置(即10deg,20deg,270deg等)的時間總是與另一層中的blip的發光一致,這個問題每隔10度停止,重新計算和開始動畫。

我可以產生一個NSTimer來激發一個查詢魔杖表示層的角度來獲取標題值的方法。然而,這使得難以保持魔杖和blip突出顯示同步,並且/或者導致一些完全跳過。這個方法在這裏有所討論:How can I callback as a CABasicAnimation is animating?

所以我的問題是,是否有任何事情可以做,以提高棒圖層旋轉的性能,而無需使用OpenGL ES重新實現控件。 (我意識到這可以在OpenGL環境中輕鬆解決,但是,在這裏使用它需要進行大量的重新設計,這是不值得的。)雖然性能問題很小,但我不能動搖那種感覺簡單而明顯的是,我可以做到這一點將允許魔杖無限期地動畫,而不會暫停執行昂貴的旋轉計算。

下面是一些代碼:

- (void)rotateWandByIncrement 
{ 
    if (wandShouldStop) 
     return; 

    CGFloat newRotationDegree = (wandRotationDegree + WAND_INCREMENT_DEGREES); 
    if (newRotationDegree >= 360) 
     newRotationDegree = 0; 


    CATransform3D rotationTransform = CATransform3DMakeRotation(DEGREES_TO_RADIANS(newRotationDegree), 0, 0, 1); 

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; 
    animation.toValue = [NSValue valueWithCATransform3D:rotationTransform]; 
    animation.duration = WAND_INCREMENT_DURATION; 
    animation.fillMode = kCAFillModeForwards; 
    animation.removedOnCompletion = FALSE; 
    animation.delegate = self; 

    [wandLayer addAnimation:animation forKey:@"transform"]; 
} 

- (void)animationDidStart:(CAAnimation *)theAnimation 
{ 
    if (wandShouldStop) 
     return; 

    NSInteger prevWandRotationDegree = wandRotationDegree - WAND_INCREMENT_DEGREES; 
    if (prevWandRotationDegree < 0) 
     prevWandRotationDegree += 360; 

    // Pulse the spriteControl 
    [[self spriteControl] pulseRayAtHeading:prevWandRotationDegree]; 
} 

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag 
{ 
    // update the rotation var 
    wandRotationDegree += WAND_INCREMENT_DEGREES; 
    if (wandRotationDegree >= 360) 
     wandRotationDegree = 0; 

    // This applies the rotation value to the model layer so that 
    // subsequent animations start where the previous one left off 
    CATransform3D rotationTransform = CATransform3DMakeRotation(DEGREES_TO_RADIANS(wandRotationDegree), 0, 0, 1); 

    [CATransaction begin]; 
    [CATransaction setDisableActions:TRUE]; 
    [wandLayer setTransform:rotationTransform]; 
    [CATransaction commit]; 

    //[wandLayer removeAnimationForKey:@"transform"]; 
    [self rotateWandByIncrement]; 
} 
+0

更新:我已經通過創建一個預先計算值的靜態數組來消除所有不必要的計算。現在我已經向自己保證,我的性能瓶頸不是昂貴的數學操作造成的。然後,我在魔杖層上實現了關鍵幀動畫,但仍然獲得稍微不平滑的旋轉。我發現切換到UIView動畫而不是CAAnimation在這種情況下提供了更流暢的動畫。到目前爲止,似乎要從CAAnimation中獲得任何真正的性能優勢,您希望避免完全使用回調並讓GPU實現其功能。 – quickthyme 2011-05-17 18:23:51

回答

1

比方說,這需要10秒的雷達,使一個完整的旋轉。

爲了讓魔杖無限期地旋轉,附加CABasicAnimation將它與它的Duration屬性設置爲10和RepeatCount屬性設置爲1e100f。

使用他們自己的實例CAKeyframeAnimation可以爲每個blips分別設置動畫。我不會寫詳細信息,但是對於每個blip,您都指定一個不透明度值的數組(我認爲不透明度是您如何淡出blipped)和一系列時間百分比(請參閱Apple的文檔)。

+0

有趣和感謝小費!目前,淡化效果是應用於每個CALayer單獨運行的動畫。我的問題是更多的魔杖相關,因爲我希望它的傳遞時機觸發單個blip圖層上的動畫。我考慮設置一個帶有36個動畫的CAAnimationGroup,每個動畫都有一個延遲值,以便它們連續運行。我希望這可以給我animationDidStop回調每個動畫。但是蘋果的文檔似乎表明,你只能獲得整個團隊的其中一個,而不是其中的每個動畫。 – quickthyme 2011-05-11 23:12:16