CoreAnimation - непрозрачность Fade In и Out Animation не работает
Я пытаюсь создать довольно простой CoreAnimation для использования в AVComposition
. Моя цель - создать CALayer
, который через различные подслои стирает заголовок внутри и снаружи, а затем исчезает в образах. Слайд-шоу, в основном. Это экспортируется в .mov с помощью AVAssetWriter
.
С помощью WWE 2011 AVEditDemo я смог получить заголовок и изображения. Проблема в том, что они все на экране в одно и то же время!
Я создал каждый слой с непрозрачностью 0.0. Затем я добавил CABasicAnimation
для уменьшения их значений с 0.0 до 1.0, используя следующий код:
CABasicAnimation *fadeInAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeInAnimation.fromValue = [NSNumber numberWithFloat:0.0];
fadeInAnimation.toValue = [NSNumber numberWithFloat:1.0];
fadeInAnimation.additive = NO;
fadeInAnimation.removedOnCompletion = YES;
fadeInAnimation.beginTime = 1.0;
fadeInAnimation.duration = 1.0;
fadeInAnimation.fillMode = kCAFillModeForwards;
[titleLayer addAnimation:fadeInAnimation forKey:nil];
Проблема, похоже, является свойством beginTime. "1.0" означает задержку, поэтому он начинается через 1 секунду после начала анимации. Тем не менее, он появляется на экране сразу. Анимированная анимация
Реверс этого кода, для постепенного исчезновения, просто изменяет fromValue на 1.0 и toValue на 0.0. Он имеет время начала 4.0 и отлично работает.
Я использую следующее для создания animatedTitleLayer
:
CATextLayer *titleLayer = [CATextLayer layer];
titleLayer.string =self.album.title;
titleLayer.font = @"Helvetica";
titleLayer.fontSize = videoSize.height / 6;
titleLayer.alignmentMode = kCAAlignmentCenter;
titleLayer.bounds = CGRectMake(0, 0, videoSize.width, videoSize.height / 6);
titleLayer.foregroundColor = [[UIColor redColor]CGColor];
titleLayer.opacity = 0.0;
Умирает изображение в анимации, начиная с 5 секунд. Как и название, их анимация затухания отлично работает.
Любая помощь будет принята с благодарностью!
Ура!
ИЗМЕНИТЬ
Ответы были полезными, но в итоге я обнаружил, что в CALayer
можно добавить только одну анимацию. Активизировалась анимация с постепенным исчезновением, поскольку она была последней.
Затем я попробовал CAAnimationGroup, но это не сработало, поскольку я изменял один и тот же путь значений ключа.
Итак, я понял, что a CAKeyframeAnimation
является лучшим для этого. Только у меня есть с этим трудности! Код теперь исчезает в порядке, но он не исчезает. Я пробовал различные fillMode, менял продолжительность и т.д. Не могу заставить его работать!
Вот мой код:
CAKeyframeAnimation *fadeInAndOut = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
fadeInAndOut.duration = 5.0;
fadeInAndOut.autoreverses = NO;
fadeInAndOut.keyTimes = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:1.0],
[NSNumber numberWithFloat:4.0],
[NSNumber numberWithFloat:5.0], nil];
fadeInAndOut.values = [NSArray arrayWithObjects: [NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:1.0],
[NSNumber numberWithFloat:1.0],
[NSNumber numberWithFloat:0.0], nil];
fadeInAndOut.beginTime = 1.0;
fadeInAndOut.removedOnCompletion = NO;
fadeInAndOut.fillMode = kCAFillModeBoth;
[titleLayer addAnimation:fadeInAndOut forKey:nil];
Ответы
Ответ 1
Я столкнулся с одной и той же проблемой, и проблема в том, что один слой не может содержать затухание.
Таким образом, вы можете добавить другую анимацию к родительскому слою, как я сделал
CALayer *parentLayer = [CALayer layer];
CALayer *animtingLayer = [CALayer layer];
//FADE IN
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.beginTime = CMTimeGetSeconds(img.startTime);
animation.duration = CMTimeGetSeconds(_timeline.transitionDuration);
animation.fromValue = [NSNumber numberWithFloat:0.0f];
animation.toValue = [NSNumber numberWithFloat:1.0f];
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeBoth;
animation.additive = NO;
[parentLayer addAnimation:animation forKey:@"opacityIN"];
//FADE OUT
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.beginTime = CMTimeGetSeconds(CMTimeAdd(img.passTimeRange.start, img.passTimeRange.duration));
animation.duration = CMTimeGetSeconds(_timeline.transitionDuration);
animation.fromValue = [NSNumber numberWithFloat:1.0f];
animation.toValue = [NSNumber numberWithFloat:0.0f];
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeBoth;
animation.additive = NO;
[animtingLayer addAnimation:animation forKey:@"opacityOUT"];
[parentLayer addSublayer:animtingLayer];
Ответ 2
Человек, так много сложных ответов. Самый простой способ - просто добавить autoreverse. Вуаля.
CABasicAnimation *fadeInAndOut = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeInAndOut.duration = 5.0;
fadeInAndOut.autoreverses = YES;
fadeInAndOut.fromValue = [NSNumber numberWithFloat:0.0];
fadeInAndOut.toValue = [NSNumber numberWithFloat:1.0];
fadeInAndOut.repeatCount = HUGE_VALF;
fadeInAndOut.fillMode = kCAFillModeBoth;
[titleLayer addAnimation:fadeInAndOut forKey:@"myanimation"];
Ответ 3
Это работает для меня:
let fadeAnimation = CAKeyframeAnimation(keyPath:"opacity")
fadeAnimation.beginTime = AVCoreAnimationBeginTimeAtZero + start
fadeAnimation.duration = duration
fadeAnimation.keyTimes = [0, 1/8.0, 5/8.0, 1]
fadeAnimation.values = [0.0, 1.0, 1.0, 0.0]
fadeAnimation.removedOnCompletion = false
fadeAnimation.fillMode = kCAFillModeForwards
layer.addAnimation(fadeAnimation, forKey:"animateOpacity")
layer.opacity = 0.0
Ответ 4
Try:
fadeInAnimation.beginTime = CACurrentMediaTime()+1.0;
Ответ 5
Я думаю, что вы ищете timeOffset
, а не beginTime
...
Ответ 6
Ядром проблемы было не понимание свойства keyTimes CAKeyframeAnimation. Этот вопрос прояснил все это и поставил меня на правильный путь:
Какое значение имеет ключевое слово в CAKeyFrameAnimation?
Ответ 7
Заимствование из ссылки, упомянутой gamblor87, и добавление моих комментариев в качестве объяснения.
//create a fadeInOut CAKeyframeAnimation on opacticy
CAKeyframeAnimation *fadeInAndOut = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
//set duration
fadeInAndOut.duration = 5.0;
//autoreverses defaults to NO so we don't need this.
//fadeInAndOut.autoreverses = NO;
//keyTimes are time points on duration timeline as a fraction of animation duration (here 5 seconds).
fadeInAndOut.keyTimes = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.20],
[NSNumber numberWithFloat:0.80],
[NSNumber numberWithFloat:1.0], nil];
//set opacity values at various points during the 5second animation
fadeInAndOut.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],//opacity 0 at 0s (corresponds to keyTime = 0s/5s)
[NSNumber numberWithFloat:1.0],//opacity 1 at 1s (corresponds to keyTime = 1s/5s)
[NSNumber numberWithFloat:1.0],//opacity 1 upto 4s (corresponds to keyTime = 4s/5s)
[NSNumber numberWithFloat:0.0],//opacity 0 at 5s (corresponds to keyTime = 5s/5s)
nil];
//delay in start of animation. What we are essentially saying is to start the 5second animation after 1second.
fadeInAndOut.beginTime = 1.0;
//don't remove the animation on completion.
fadeInAndOut.removedOnCompletion = NO;
//fill mode. In most cases we won't need this.
fadeInAndOut.fillMode = kCAFillModeBoth;
//add the animation to layer
[titleLayer addAnimation:fadeInAndOut forKey:nil];
Ответ 8
LenK ответ работал отлично для меня. Если кому-то интересно, я переписал для Obj-C (обратите внимание, что я также немного изменил ключевые фреймы на fade in):
CAKeyframeAnimation *fadeInAndOutAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
fadeInAndOutAnimation.beginTime = CACurrentMediaTime() + beginTime;
fadeInAndOutAnimation.duration = duration;
fadeInAndOutAnimation.keyTimes = @[@0.0, @( 2.0 / 8.0 ), @( 5.0 / 8.0 ), @1.0];
fadeInAndOutAnimation.values = @[@0.0, @1.0, @1.0, @0.0];
fadeInAndOutAnimation.removedOnCompletion = false;
fadeInAndOutAnimation.fillMode = kCAFillModeForwards;
Ответ 9
Точка - это имя ключа. Вы должны установить ключ непрозрачности.
layer.add(animation, forKey: nil) // Not Working
layer.add(animation, forKey: "opacity") // Working
Проверьте код образца. Я тестировал в Swift 4
let animation = CAKeyframeAnimation()
animation.duration = 1.53
animation.autoreverses = false
animation.keyTimes = [0, 0.51, 0.85, 1.0]
animation.values = [0.5, 0.5, 1.0, 0.5]
animation.beginTime = 0
animation.isRemovedOnCompletion = false
animation.fillMode = kCAFillModeBoth
animation.repeatCount = .greatestFiniteMagnitude
layer.add(animation, forKey: "opacity")
Ответ 10
Посмотрите на мой ответ fooobar.com/questions/286995/...
Вкратце: для использования beginTime
вы должны установить fillMode в kCAFillModeBackwards
на объект анимации.
Ответ 11
Альтернативным способом является использование CAAnimationGroup. CAKeyframeAnimation также отлично подходит для пользовательского интерфейса. Этот код отлично работает в пользовательском интерфейсе для анимации шоу в реальном времени. Но не будет работать вообще в AVVideoCompositionCoreAnimationTool
- прокрутите вниз, если вам это нужно. Это не готовый код для копирования-вставки, но вы можете получить эту идею. Кроме того, вы можете добавить анимацию добавления в группу:
for (HKAnimatedLayer *animLayer in layersList) {
overlayLayer = [CALayer layer];
[overlayLayer setContents:(id)[animLayer.image CGImage]];
overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
[overlayLayer setMasksToBounds:YES];
NSMutableArray *animations = [NSMutableArray array];
// Step 1
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.toValue = @(0);
animation.duration = kLayerFadeDuration;
animation.beginTime = kMovieDuration/5;
animation.fillMode = kCAFillModeForwards;
[animations addObject:animation];
}
{
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.toValue = @(1.0);
animation.duration = kLayerFadeDuration;
animation.beginTime = kMovieDuration*2/3;
animation.fillMode = kCAFillModeForwards;
[animations addObject:animation];
}
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = animations;
animationGroup.duration = kMovieDuration;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.removedOnCompletion = YES;
[overlayLayer addAnimation:animationGroup forKey:nil];
[parentLayer addSublayer:overlayLayer];
}
Здесь небольшая заметка об анимации на слоях для AVVideoCompositionCoreAnimationTool
. Вы можете увидеть соответствующее изображение gif (заголовки должны появляться и исчезать один за другим). Для решения этой проблемы я использую 2 отдельных CALayer
, потому что по какой-то причине на одном слое 2 opaque
выполняются анимации на нескольких слоях.
![AVVideoCompositionCoreAnimationTool]()
// set up the parent layer
CALayer *parentLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
// one layer for one animation
CALayer *overlayLayer, *barrierLayer;
CABasicAnimation *animation;
for (HKAnimatedLayer *animLayer in layersList) {
overlayLayer = [CALayer layer];
overlayLayer.contents = (id)[animLayer.image CGImage];
overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
overlayLayer.masksToBounds = YES;
// layer with appear animation
if (animLayer.fromTime != 0 && (animLayer.fromTime - kLayerFadeDuration)>0) {
overlayLayer.opacity = 0.0;
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = @(0);
animation.toValue = @(1);
animation.additive = NO;
animation.removedOnCompletion = NO;
animation.beginTime = animLayer.fromTime - kLayerFadeDuration;
animation.duration = kLayerFadeDuration;
animation.fillMode = kCAFillModeForwards;
[overlayLayer addAnimation:animation forKey:@"fadeIn"];
}
if (animLayer.toTime == kMovieDuration) {
[parentLayer addSublayer:overlayLayer];
} else { // layer with dissappear animation
barrierLayer = [CALayer layer];
barrierLayer.frame = CGRectMake(0, 0, size.width, size.height);
barrierLayer.masksToBounds = YES;
[barrierLayer addSublayer:overlayLayer];
animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
animation.fromValue = @(1);
animation.toValue = @(0);
animation.additive = NO;
animation.removedOnCompletion = NO;
animation.beginTime = animLayer.toTime;
animation.duration = kLayerFadeDuration;
animation.fillMode = kCAFillModeForwards;
[overlayLayer addAnimation:animation forKey:@"fadeOut"];
[parentLayer addSublayer:barrierLayer];
}
}
И в конце мы можем получить правильную последовательность анимации ![right animation]()