programing

애니메이션 완료 후 CABasic Animation이 초기 값으로 재설정됨

i4 2023. 6. 5. 23:36
반응형

애니메이션 완료 후 CABasic Animation이 초기 값으로 재설정됨

저는 애니메이션이 완료된 후 CAL레이어를 회전시키고 최종 위치에서 정지하려고 합니다.

그러나 애니메이션이 완료된 후에는 초기 위치로 재설정됩니다.

(xcode 문서에는 애니메이션이 속성 값을 업데이트하지 않을 것이라고 명시되어 있습니다.)

이를 달성하는 방법에 대한 모든 제안.

여기 제 대답과 크리슈난의 대답이 합쳐진 답입니다.

cabasicanimation.fillMode = kCAFillModeForwards;
cabasicanimation.removedOnCompletion = NO;

은 기값은 입다니입니다.kCAFillModeRemoved(지금 보고 있는 재설정 동작입니다.)

removedOnCompletion의 문제는 UI 요소가 사용자 상호 작용을 허용하지 않는다는 것입니다.

I 기법은 애니메이션의 FROM 값과 객체의 TO 값을 설정하는 것입니다.애니메이션은 시작하기 전에 TO 값을 자동으로 채우고 제거되면 개체가 올바른 상태로 유지됩니다.

// fade in
CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath: @"opacity"];
alphaAnimation.fillMode = kCAFillModeForwards;

alphaAnimation.fromValue = NUM_FLOAT(0);
self.view.layer.opacity = 1;

[self.view.layer addAnimation: alphaAnimation forKey: @"fade"];

코어 애니메이션은 모델 레이어와 프레젠테이션 레이어의 두 계층 계층을 유지합니다.애니메이션이 진행 중일 때 모델 레이어는 실제로 손상되지 않고 초기 값을 유지합니다.기본적으로 애니메이션은 완료되면 제거됩니다.그런 다음 프레젠테이션 계층은 모델 계층의 값으로 돌아갑니다.

순단설 설정하기removedOnCompletionNO애니메이션이 제거되지 않고 메모리가 낭비된다는 의미입니다.또한 모델 계층과 프레젠테이션 계층이 더 이상 동기화되지 않으므로 잠재적인 버그가 발생할 수 있습니다.

따라서 모델 계층에서 직접 속성을 최종 값으로 업데이트하는 것이 더 나은 솔루션이 될 수 있습니다.

self.view.layer.opacity = 1;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = 0;
animation.toValue = 1;
[self.view.layer addAnimation:animation forKey:nil];

위 코드의 첫 번째 줄로 인해 암시적인 애니메이션이 발생하는 경우, 해제를 시도합니다.

[CATransaction begin];
[CATransaction setDisableActions:YES];
self.view.layer.opacity = 1;
[CATransaction commit];

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = 0;
animation.toValue = 1;
[self.view.layer addAnimation:animation forKey:nil];

다음 속성을 설정합니다.

animationObject.removedOnCompletion = NO;

간단히 키를 설정할 수 있습니다.CABasicAnimationposition계층에 추가할 때 사용합니다.이렇게 하면 실행 루프의 현재 패스 위치에서 수행된 암시적 애니메이션이 재정의됩니다.

CGFloat yOffset = 30;
CGPoint endPosition = CGPointMake(someLayer.position.x,someLayer.position.y + yOffset);

someLayer.position = endPosition; // Implicit animation for position

CABasicAnimation * animation =[CABasicAnimation animationWithKeyPath:@"position.y"]; 

animation.fromValue = @(someLayer.position.y);
animation.toValue = @(someLayer.position.y + yOffset);

[someLayer addAnimation:animation forKey:@"position"]; // The explicit animation 'animation' override implicit animation

2011 Apple WWDC Video Session 421 - Core Animation Essentials(비디오 중간)에 대한 자세한 정보를 얻을 수 있습니다.

그냥 코드 안에 넣어두세요.

CAAnimationGroup *theGroup = [CAAnimationGroup animation];

theGroup.fillMode = kCAFillModeForwards;

theGroup.removedOnCompletion = NO;

CALayer에는 모델 레이어와 프레젠테이션 레이어가 있습니다.애니메이션이 진행되는 동안 프레젠테이션 계층은 모델과 독립적으로 업데이트됩니다.애니메이션이 완료되면 프레젠테이션 계층이 모델의 값으로 업데이트됩니다.애니메이션이 종료된 후에 방해 점프를 방지하려면 두 레이어를 동기화하는 것이 중요합니다.

끝 값을 알고 있으면 모형을 직접 설정할 수 있습니다.

self.view.layer.opacity = 1;

그러나 끝 위치를 모르는 애니메이션(예: 사용자가 일시 중지했다가 다시 되돌릴 수 있는 느린 페이드)이 있는 경우 프레젠테이션 레이어를 직접 쿼리하여 현재 값을 찾은 다음 모델을 업데이트할 수 있습니다.

NSNumber *opacity = [self.layer.presentationLayer valueForKeyPath:@"opacity"];
[self.layer setValue:opacity forKeyPath:@"opacity"];

을 끌어오는 키 하거나 회전할 ( 프테이션계예값끌것또스는회특다유니경키합용히로에전는은케어일링오을레젠층에서예▁pulling:(path다니유▁is합용▁scaling▁(es특▁the▁key:transform.scale,transform.rotation)

그래서 저의 문제는 제가 물체를 회전시키려고 하는 것이었습니다. 그래서 저는 각각의 움직임에 동일한 애니메이션을 여러 개 가지고 있었습니다.둘 다 먹었어요.fillMode = kCAFillModeForwards그리고.isRemovedOnCompletion = false하지만 소용이 없어.의 경우, 새 애니메이션을 추가할 때마다 애니메이션 키가 다른지 확인해야 했습니다.

let angle = // here is my computed angle
let rotate = CABasicAnimation(keyPath: "transform.rotation.z")
rotate.toValue = angle
rotate.duration = 0.1
rotate.isRemovedOnCompletion = false
rotate.fillMode = CAMediaTimingFillMode.forwards

head.layer.add(rotate, forKey: "rotate\(angle)")

효과:

let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 0.3

someLayer.opacity = 1 // important, this is the state you want visible after the animation finishes.
someLayer.addAnimation(animation, forKey: "myAnimation")

코어 애니메이션은 애니메이션이 진행되는 동안 일반 레이어 위에 '프레젠테이션 레이어'를 표시합니다.따라서 애니메이션이 완료되고 프레젠테이션 계층이 사라지면 불투명도(또는 원하는 대로)를 표시할 대상으로 설정합니다.애니메이션을 추가하기 전에 라인에서 이 작업을 수행하여 애니메이션이 완료될 때 깜박임을 방지합니다.

지연을 원하는 경우 다음을 수행합니다.

let animation = CABasicAnimation(keyPath: "opacity")
animation.fromValue = 0
animation.toValue = 1
animation.duration = 0.3
animation.beginTime = someLayer.convertTime(CACurrentMediaTime(), fromLayer: nil) + 1
animation.fillMode = kCAFillModeBackwards // So the opacity is 0 while the animation waits to start.

someLayer.opacity = 1 // <- important, this is the state you want visible after the animation finishes.
someLayer.addAnimation(animation, forKey: "myAnimation")

마지막으로, 'removedOnCompletion = false'를 사용하면 레이어가 최종적으로 폐기될 때까지 CAA 애니메이션이 누출됩니다. 피하십시오.

를사하않고를 하지 않고 합니다.removedOnCompletion

이 기술을 사용해 볼 수 있습니다.

self.animateOnX(item: shapeLayer)

func animateOnX(item:CAShapeLayer)
{
    let endPostion = CGPoint(x: 200, y: 0)
    let pathAnimation = CABasicAnimation(keyPath: "position")
    //
    pathAnimation.duration = 20
    pathAnimation.fromValue = CGPoint(x: 0, y: 0)//comment this line and notice the difference
    pathAnimation.toValue =  endPostion
    pathAnimation.fillMode = kCAFillModeBoth

    item.position = endPostion//prevent the CABasicAnimation from resetting item's position when the animation finishes

    item.add(pathAnimation, forKey: nil)
}

순단설 설정하기fillMode그리고.removedOnCompletion나한텐 안 통했어요아래의 모든 속성을 CABasic Animation 개체로 설정하여 문제를 해결했습니다.

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.duration = 0.38f;
ba.fillMode = kCAFillModeForwards;
ba.removedOnCompletion = NO;
ba.autoreverses = NO;
ba.repeatCount = 0;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.85f, 0.85f, 1.0f)];
[myView.layer addAnimation:ba forKey:nil];

는 이코는변다니됩환드를 변환합니다.myView크기의 85%까지(3차원 변경 없음).

@Leslie Godwin의 대답은 그다지 좋지 않습니다. "self.view.layer.opcity = 1;"은 즉시 수행됩니다(약 1초 소요). 의심이 있으면 alphaAnimation.duration을 10.0으로 수정하십시오.당신은 이 선을 제거해야 합니다.

따라서 fillMode를 kCAfillModeForwards로 수정하고 OnCompletion을 NO로 제거하면 애니메이션이 레이어에 남아 있게 됩니다.애니메이션 대리자를 수정하고 다음과 같은 작업을 시도하는 경우:

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
 [theLayer removeAllAnimations];
}

...이 줄을 실행하는 순간 계층이 즉시 복원됩니다.그것이 우리가 피하고 싶었던 것입니다.

도면층에서 애니메이션을 제거하기 전에 도면층 속성을 수정해야 합니다.사용해 보십시오.

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
     if([anim isKindOfClass:[CABasicAnimation class] ]) // check, because of the cast
    {
        CALayer *theLayer = 0;
        if(anim==[_b1 animationForKey:@"opacity"])
            theLayer = _b1; // I have two layers
        else
        if(anim==[_b2 animationForKey:@"opacity"])
            theLayer = _b2;

        if(theLayer)
        {
            CGFloat toValue = [((CABasicAnimation*)anim).toValue floatValue];
            [theLayer setOpacity:toValue];

            [theLayer removeAllAnimations];
        }
    }
}

가장 쉬운 해결책은 암시적인 애니메이션을 사용하는 것입니다.이렇게 하면 모든 문제를 해결할 수 있습니다.

self.layer?.backgroundColor = NSColor.red.cgColor;

기간 등을 사용자 지정하려면 다음을 사용할 수 있습니다.NSAnimationContext:

    NSAnimationContext.beginGrouping();
    NSAnimationContext.current.duration = 0.5;
    self.layer?.backgroundColor = NSColor.red.cgColor;
    NSAnimationContext.endGrouping();

참고: 이것은 macOS에서만 테스트됩니다.

처음에는 애니메이션을 보지 못했습니다.문제는 뷰 지원 계층의 계층이 암시적으로 애니메이션화되지 않는다는 것입니다.이 문제를 해결하려면 뷰를 레이어 백업으로 설정하기 전에 직접 레이어를 추가해야 합니다.

이 방법의 예는 다음과 같습니다.

override func awakeFromNib() {
    self.layer = CALayer();
    //self.wantsLayer = true;
}

사용.self.wantsLayer제 테스트에는 아무런 차이가 없었지만, 제가 모르는 부작용이 있을 수 있습니다.

removedOnCompletion 플래그가 false로 설정되어 있고 fillMode가 kCAfillModeForwards로 설정되어 있는 것도 저에게는 작동하지 않는 것 같습니다.

레이어에 새 애니메이션을 적용하면 애니메이션 개체가 초기 상태로 재설정된 다음 해당 상태에서 애니메이션이 실행됩니다.추가로 수행해야 할 작업은 다음과 같이 새 애니메이션을 설정하기 전에 프레젠테이션 계층의 속성에 따라 모델 계층의 원하는 속성을 설정하는 것입니다.

someLayer.path = ((CAShapeLayer *)[someLayer presentationLayer]).path;
[someLayer addAnimation:someAnimation forKey:@"someAnimation"];

여기 놀이터의 샘플이 있습니다.

import PlaygroundSupport
import UIKit

let resultRotation = CGFloat.pi / 2
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: 200.0, height: 300.0))
view.backgroundColor = .red

//--------------------------------------------------------------------------------

let rotate = CABasicAnimation(keyPath: "transform.rotation.z") // 1
rotate.fromValue = CGFloat.pi / 3 // 2
rotate.toValue = resultRotation // 3
rotate.duration = 5.0 // 4
rotate.beginTime = CACurrentMediaTime() + 1.0 // 5
// rotate.isRemovedOnCompletion = false // 6
rotate.fillMode = .backwards // 7

view.layer.add(rotate, forKey: nil) // 8
view.layer.setAffineTransform(CGAffineTransform(rotationAngle: resultRotation)) // 9

//--------------------------------------------------------------------------------

PlaygroundPage.current.liveView = view
  1. 애니메이션 모델 만들기
  2. 애니메이션의 시작 위치를 설정합니다(현재 레이어 레이아웃에 따라 생략할 수 있음)
  3. 애니메이션의 종료 위치 설정
  4. 애니메이션 기간 설정
  5. 애니메이션을 잠시 지연
  6. 설정 안 함false로.isRemovedOnCompletion애니메이션이 완료된 후 Core Animation을 청소합니다.
  7. 다음은 요령의 첫 번째 부분입니다. 애니메이션이 시작되기도 전에 Core Animation에게 애니메이션을 시작 위치(2단계에서 설정한 위치)로 배치하라고 말합니다. 시간을 거꾸로 연장하십시오.
  8. 준비된 애니메이션 개체를 복사하여 레이어에 추가하고 지연 후 애니메이션을 시작합니다(5단계에서 설정).
  9. 두 번째 부분레이어의 올바른위치를 설정하는 것입니다. 애니메이션이 삭제되면 레이어가 올바른 위치에 표시됩니다.

언급URL : https://stackoverflow.com/questions/6059054/cabasicanimation-resets-to-initial-value-after-animation-completes

반응형