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