답변:
여기에 답이 있습니다. 제 답변과 Krishnan의 조합입니다.
cabasicanimation.fillMode = kCAFillModeForwards;
cabasicanimation.removedOnCompletion = NO;
기본값은 kCAFillModeRemoved
입니다. 보고있는 재설정 동작은 무엇입니까?
removedOnCompletion의 문제점은 UI 요소가 사용자 상호 작용을 허용하지 않는다는 것입니다.
기술은 애니메이션의 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"];
alphaAnimation.beginTime = 1;
또한 fillMode
내가 말할 수있는 한 필요하지 않습니다 ...?
beginTime
상대하지, 당신은 사용해야 예 :CACurrentMediaTime()+1;
다음 속성을 설정하십시오.
animationObject.removedOnCompletion = NO;
그냥 코드 안에 넣으십시오
CAAnimationGroup *theGroup = [CAAnimationGroup animation];
theGroup.fillMode = kCAFillModeForwards;
theGroup.removedOnCompletion = NO;
당신은 단순히의 주요 설정할 수 있습니다 CABasicAnimation
에 position
당신이 레이어에 추가 할 때입니다. 이렇게하면 실행 루프의 현재 패스 위치에서 수행 된 암시 적 애니메이션이 재정의됩니다.
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 비디오 세션 421-Core Animation Essentials (비디오 중간)에 대한 자세한 정보를 얻을 수 있습니다.
someLayer.position = endPosition;
. 그리고 WWDC에 대한 심판에 감사드립니다!
CALayer에는 모델 계층과 프레젠테이션 계층이 있습니다. 애니메이션 중 프레젠테이션 레이어는 모델과 독립적으로 업데이트됩니다. 애니메이션이 완료되면 프리젠 테이션 레이어가 모델의 값으로 업데이트됩니다. 애니메이션이 끝난 후 삐걱 거리는 점프를 피하려면 중요한 것은 두 레이어의 동기화를 유지하는 것입니다.
최종 값을 알고 있다면 모델을 직접 설정할 수 있습니다.
self.view.layer.opacity = 1;
그러나 끝 위치를 모르는 애니메이션이있는 경우 (예 : 사용자가 일시 정지 한 후 반전 할 수있는 느린 페이드) 프레젠테이션 레이어를 직접 쿼리하여 현재 값을 찾은 다음 모델을 업데이트 할 수 있습니다.
NSNumber *opacity = [self.layer.presentationLayer valueForKeyPath:@"opacity"];
[self.layer setValue:opacity forKeyPath:@"opacity"];
프리젠 테이션 레이어에서 값을 가져 오는 것도 스케일링 또는 회전 키 패스에 특히 유용합니다. (예를 들어 transform.scale
, transform.rotation
)
사용하지 않고 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 = 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)")
단순히 설정 fillMode
하고 removedOnCompletion
나에게 효과가 없었습니다. 아래의 모든 속성을 CABasicAnimation 객체 로 설정하여 문제를 해결했습니다 .
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 차원은 변경되지 않음)로 변환됩니다.
핵심 애니메이션은 두 가지 계층 계층, 즉 모델 계층 과 프레젠테이션 계층을 유지 관리 합니다. 애니메이션이 진행중인 경우 모델 레이어는 그대로 유지되며 초기 값을 유지합니다. 기본적으로 애니메이션은 완료되면 제거됩니다. 그런 다음 프리젠 테이션 레이어는 모델 레이어의 값으로 돌아갑니다.
간단히 설정 removedOnCompletion
에 NO
애니메이션이 제거되지 않습니다 수단 및 폐기물 메모리. 또한 모델 레이어와 프리젠 테이션 레이어는 더 이상 동기화되지 않으므로 잠재적 인 버그가 발생할 수 있습니다.
따라서 모델 레이어의 속성을 최종 값으로 직접 업데이트하는 것이 더 나은 솔루션입니다.
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];
이것은 작동합니다 :
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'를 사용하면 레이어가 결국 폐기 될 때까지 CAAnimations가 누출됩니다. 피하십시오.
@Leslie Godwin의 답변은 "self.view.layer.opacity = 1;" 즉시 완료됩니다 (약 1 초 정도 소요). 의심스러운 경우 alphaAnimation.duration을 10.0으로 수정하십시오. 이 줄을 제거해야합니다.
따라서 fillMode를 kCAFillModeForwards로, removedOnCompletion을 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];
}
}
}
removedOnCompletion 플래그가 false로 설정되고 fillMode가 kCAFillModeForwards로 설정되어있는 것 같습니다.
레이어에 새 애니메이션을 적용하면 애니메이션 객체가 초기 상태로 재설정 된 다음 해당 상태에서 애니메이션이 적용됩니다. 추가로해야 할 일은 새로운 애니메이션을 설정하기 전에 프리젠 테이션 레이어의 속성에 따라 모델 레이어의 원하는 속성을 설정하는 것입니다.
someLayer.path = ((CAShapeLayer *)[someLayer presentationLayer]).path;
[someLayer addAnimation:someAnimation forKey:@"someAnimation"];
가장 쉬운 해결책은 암시 적 애니메이션을 사용하는 것입니다. 이것은 당신을 위해 그 모든 문제를 다룰 것입니다 :
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
테스트에서 아무런 차이가 없었지만 모르는 부작용이있을 수 있습니다.
놀이터의 샘플은 다음과 같습니다.
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
false
에 isRemovedOnCompletion
- 애니메이션이 완료된 후 코어 애니메이션 청소하자
.presentation()
"최종, 본"값을 얻기 위해 본다 . 아래에서 정답 레이어를 찾아서 프리젠 테이션 레이어로 완료된 것을 설명하십시오.