0

CAAnimation은 표준 "animationDidStart :"/ "animationDidStop :"메서드 이외의 콜백 함수를 할당하는 메커니즘을 제공하지 않습니다.CABasicAnimation 콜백 대신 사용할 수 있습니까?

중복되는 2 개의 CALayers를 사용하는 맞춤 UIControl이 있습니다. 이 컨트롤의 목적은 구식 수중 음파 탐지기와 비슷합니다. 최상위 레이어의 내용에는 끊임없이 회전하는 이미지가 포함됩니다 (이 레이어를 "지팡이"라고 함). 그 레이어 아래에는 지팡이가 지평선을지나 감에 따라 화면을 렌더링하는 "spriteControl"레이어가 있습니다.

blip이 나타내는 개체는 pre-fetched이며 spriteControl에 의해 보이지 않는 CAShapeLayers로 구성됩니다. CABasicAnimation을 사용하여 한 번에 10 도씩 막대를 회전 한 다음 "animationDidStop :"메서드를 사용하여 spriteControl에서 막대 레이어의 현재 회전 값 (일명 표제)을 가져 와서 알파 설정을 애니메이션합니다. blip in 및 fade out 효과를 시뮬레이트하기 위해 1.0에서 0.0. 마지막으로 프로세스가 무한정 다시 시작됩니다.

CAAnimation 콜백을 사용하는이 방법은 지팡이가 "ping"위치 (즉, 10deg, 20deg, 270deg 등)에 도달하는 타이밍이 다른 레이어의 blips 조명과 항상 일치하도록합니다. 애니메이션을 10도 간격으로 멈추고 재 계산하고 시작하는이 문제.

막대 값을 얻기 위해 지팡이의 프리젠 테이션 레이어의 각도를 쿼리하는 메소드를 실행하는 NSTimer를 생성 할 수 있습니다. 그러나 막대와 지주 강조 표시를 동기화 상태로 유지하거나 일부를 건너 뛰는 것이 더 어려워집니다. 이 접근법은 조금 여기에 설명되어 있습니다 : How can I callback as a CABasicAnimation is animating?

제 질문은 내가 OpenGL ES를 사용하여 컨트롤을 reimplementing하지 않고 지팡이 레이어 회전의 성능을 향상시키기 위해 할 수있는 일이 있는지 여부입니다. (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

업데이트 : 나는 사전 계산 된 값의 정적 배열을 만들어 모든 불필요한 계산을 제거했습니다. 이제는 성능 병목 현상이 값 비싼 수학 연산으로 인해 발생하지 않는다는 것을 확신했습니다. 그런 다음 지팡이 레이어에서 키 프레임 애니메이션을 구현했지만 약간 더 부드럽게 회전하지는 못합니다. 실제로 CAAnimation 대신 UIView 애니메이션으로 전환하면이 상황에서보다 부드러운 애니메이션이 제공된다는 사실을 발견했습니다. 지금까지 CAAnimation에서 실제 성능 향상을 얻으려는 것 같습니다. 콜백을 사용하지 말고 GPU가 그 일을하도록하십시오. – quickthyme

답변

1

하는의 그것이 하나의 완전한 회전을 만들기 위해 레이더 10 초 정도 걸립니다 가정 해 봅시다 : 여기

몇 가지 코드입니다.

지팡이를 무한대로 회전하려면 Duration 속성을 10으로 설정하고 RepeatCount 속성을 1e100f로 설정하고 CABasicAnimation을 부착하십시오.

이미지는 자신의 인스턴스 CAKeyframeAnimation을 사용하여 각각 애니메이션으로 만들 수 있습니다. 세부 사항을 쓰지는 않겠지 만, 각 블립에 대해 불투명도 값 배열 (불투명도는 어떻게 페이드 아웃하는지)과 시간 비율 배열을 지정합니다 (Apple 설명서 참조).

+0

재미 있고 팁을 주셔서 감사합니다! 현재 페이딩 효과는 자체적으로 실행되는 각 CALayer 블립에 적용된 애니메이션입니다.내 이슈는 개별 패스 레이어에서 애니메이션을 트리거하기 위해 지나가는 타이밍을 원하기 때문에 더 문제가됩니다. CAAnimationGroup을 36 개의 애니메이션으로 설정하는 방법에 대해 생각해 보았습니다. 각 애니메이션은 지연 값을 설정하여 연속적으로 실행됩니다. 애니메이션마다 animationDidStop 콜백을 주길 바랬습니다. 그러나 애플의 문서에 따르면, 그 안에있는 각각의 애니메이션보다는 전체 그룹을위한 것 중 하나를 얻는다. – quickthyme

관련 문제