ios - transiciones - que es animacion de salida
CoreAnimation-Opacidad La animaciĆ³n de entrada y salida no funciona (11)
Estoy intentando crear un CoreAnimation bastante simple para usar en una AVComposition
. Mi objetivo es crear un CALayer
que, a través de varias subcapas, difumina un título dentro y fuera, luego se desvanece en una imagen de salida. Una presentación de diapositivas, básicamente. Esto se está exportando a un .mov usando AVAssetWriter
.
Con la ayuda de la WWDC 2011 AVEditDemo, he podido obtener un título y las imágenes que aparecen. ¡El problema es que todos están en pantalla al mismo tiempo!
He creado cada capa con una opacidad de 0.0. Luego agregué un CABasicAnimation
para CABasicAnimation
de 0.0 a 1.0, usando el siguiente código:
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];
El problema parece ser la propiedad ''beginTime''. El "1.0" está destinado a ser un retraso, por lo que comienza 1 segundo después del inicio de la animación. Sin embargo, está apareciendo en la pantalla de inmediato. Una animación de fundido
El reverso de este código, para el desvanecimiento, simplemente cambia el valor de FromValue a 1.0 y el de toValue a 0.0. Tiene un tiempo de inicio de 4.0 y funciona perfectamente.
Estoy usando lo siguiente para crear el 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;
La imagen que se desvanece en las animaciones tiene un tiempo de inicio de 5 segundos. Al igual que el título, sus animaciones de desvanecimiento funcionan bien.
Cualquier ayuda sería muy apreciada!
¡Aclamaciones!
EDITAR
Las respuestas fueron útiles, pero al final descubrí que solo se podía agregar una animación a un CALayer
. La animación de desvanecimiento funcionó ya que fue la última que se agregó.
Luego probé un CAAnimationGroup, pero esto no funcionó ya que estaba modificando la misma ruta de valor clave.
Así que me he dado cuenta de que CAKeyframeAnimation
es lo mejor para esto. Solo que estoy teniendo un poco de dificultad con eso también! El código ahora se está desvaneciendo, pero no se está desvaneciendo. He probado varios modos de relleno, cambié la duración, etc. ¡¡No puedo hacer que funcione !!
Aquí está mi código:
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];
Creo que estás buscando timeOffset
, no beginTime
...
El núcleo del problema no era comprender la propiedad keyTimes de un CAKeyframeAnimation. Esta pregunta lo aclaró todo y me puso en el camino correcto:
El punto es el nombre clave. Tienes que configurar la tecla de opacidad.
layer.add(animation, forKey: nil) // Not Working
layer.add(animation, forKey: "opacity") // Working
Compruebe el código de muestra. He probado en 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")
Esto funciona para mí:
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
Hombre, tantas respuestas complicadas. La forma más sencilla es simplemente agregar autoreverse. Voila
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"];
La forma alternativa es el uso de CAAnimationGroup. CAKeyframeAnimation también funciona bien para la interfaz de usuario. Este código funciona bien en la interfaz de usuario para mostrar la animación en tiempo real. Pero no funcionará en absoluto en AVVideoCompositionCoreAnimationTool
; desplácese hacia abajo si lo necesita. No es un código listo para copiar y pegar, pero puede obtener la idea. Además, puede agregar animaciones de adición al grupo:
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];
}
Aquí una pequeña nota sobre la animación en capas para AVVideoCompositionCoreAnimationTool
. Puedes ver la imagen gif relevante (los títulos deben aparecer y desaparecer uno por uno). Para resolver este problema, uso 2 CALayer
separados porque, por alguna razón, en una capa 2, se CALayer
las animaciones opaque
de varias capas.
// 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];
}
}
Y al final, podemos obtener la secuencia de animación adecuada.
La respuesta de funcionó perfectamente para mí. Si alguien está interesado, reescribí para Obj-C (nota que también cambié ligeramente los fotogramas clave en el fundido):
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;
Me enfrento al mismo problema y el problema es que una capa no puede contener la aparición y desaparición. Así que puedes agregar la otra animación a la capa principal como lo hice
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];
Mira mi respuesta https://.com/a/44204846/667483
En resumen: para usar beginTime
, debe establecer fillMode en kCAFillModeBackwards
en su objeto de animación.
Tomando prestado el enlace mencionado por gamblor87 y agregando mis comentarios como explicación.
//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];
Tratar:
fadeInAnimation.beginTime = CACurrentMediaTime()+1.0;