2012-01-03 12 views
19

Estoy intentando crear una CoreAnimation bastante simple para usarla en un AVComposition. Mi objetivo es crear un CALayer que, a través de varias subcapas, desvanece un título de entrada y salida, luego se desvanece en las imágenes de salida. Una presentación de diapositivas, básicamente. Esto se está exportando a .mov usando AVAssetWriter.CoreAnimation - Animación de fundido de opacidad de entrada y salida no funciona

Con la ayuda de la WWDC 2011 AVEditDemo, he podido obtener un título y que aparezcan las imágenes. ¡El problema es que están todos en la pantalla al mismo tiempo!

He creado cada capa con una opacidad de 0.0. entonces he añadido un CABasicAnimation a desvanecerse ellas 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 comienzo de la animación. Sin embargo, está apareciendo en la pantalla de inmediato. Una animación de fundido de salida

El reverso de este código, para el fundido de salida, simplemente cambia el fromValue a 1.0 y toValue a 0.0. Tiene un tiempo de inicio de 4.0 y funciona perfectamente.

estoy usando el 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; 

El fundido imágenes de una animación tienen un beginTime 5 segundos de diferencia. Al igual que el título, sus animaciones de fundido funcionan bien.

Cualquier ayuda sería muy apreciada!

¡Salud!

EDITAR

Las respuestas eran útiles, pero al final he descubierto que sólo un monigote puede ser añadido a una CALayer. La animación de fundido estaba funcionando ya que era la última añadida.

Probé un CAAnimationGroup, pero esto no funcionó ya que estaba modificando la misma ruta de valor de clave.

Así que me he dado cuenta de que un CAKeyframeAnimation es el mejor para esto. ¡Solo que también estoy teniendo dificultades con eso! El código ahora se está desvaneciendo bien, pero no se está desvaneciendo. Probé varios fillMode, 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]; 
+0

así que ¿está tratando de tener todas las capas posicionadas y configuradas con anticipación, o puede agregarlas a medida que avanza la transición de las diapositivas? – nielsbot

+0

Estoy posicionando y configurando antes de tiempo. Lo descubrí gracias a esta publicación: http://stackoverflow.com/questions/2184803/what-kind-of-value-is-keytime-in-an-cakeyframeanimation – gamblor87

+0

¿Has podido exportar un CALayer al video? Estoy atrapado en eso ahora. Si tiene algún consejo, responda a mi pregunta. ¡Gracias! http://stackoverflow.com/questions/10285175/avfoundation-exporting-calayers-only –

Respuesta

27

me encuentro ante el mismo problema y el problema es - una capa no puede contener fundido de entrada y salida. para que pueda 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]; 
+1

Nunca lo hubiera averiguado. Gracias @comonitos –

+0

@DavidJohnSmith me alegro de ayudar! – comonitos

+0

Tal vez se deba a iOS 7 SDK's 2013-14 update o algo que hice de manera diferente, pero agregar ** múltiples ** animaciones a una ** capa ** es posible actualmente, por lo que es innecesario usar la capa adicional @comonitos – petershine

1

Probar:

fadeInAnimation.beginTime = CACurrentMediaTime()+1.0; 
+0

No parece marcar la diferencia. Por favor mira mi edición. – gamblor87

1

Creo que estás buscando timeOffset, no beginTime ...

+0

Gracias por avisarme de esta propiedad. ¡Ha ayudado de otras maneras! Por favor mira mi edición. – gamblor87

1

endeudamiento desde el enlace mencionado por gamblor87 y añadir 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]; 
+1

fadeInAndOut.beginTime = 1.0 no funciona, necesita usar CACurrentMediaTime() + 1; – Jay

23

Hombre, muchas respuestas complicadas. La forma más simple 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"]; 
+2

Esta solución inicia el fundido de salida tan pronto como se completa el fundido. Supongo que OP quiere que el título se desvanezca, se mantenga visible por un momento y luego desaparezca. – oskare

+1

De hecho la mejor respuesta. Añadiría para aquellos que están luchando, también es posible que desee agregar [suView setWantsLayer: YES]; antes de obtener la capa de tu vista. Por defecto, las vistas no tienen capas. – Borzh

2

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 
+0

Buena respuesta :) en func – YannickSteph

1

LenK 's respuesta funcionó a la perfección para mí. Si alguien está interesado, me re-escribí para Obj-C (tenga en cuenta que también cambió ligeramente los fotogramas clave en el aumento gradual):

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; 
+0

Esto funcionó bien para mí, pero necesita agregar una línea adicional: 'fadeInAndOutAnimation.repeatCount = HUGE_VALF;'. De lo contrario, la vista se desvanece una vez y nunca vuelve a aparecer. – rmaddy

1

La forma alternativa es utilizar CAAnimationGroup. CAKeyframeAnimation también funciona bien para la IU. 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 está listo para copiar y pegar, pero puede hacerse una idea. Además, se puede agregar animaciones además del 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í pequeña nota acerca de la animación en capas para AVVideoCompositionCoreAnimationTool. Puede ver la imagen gif relevante (los títulos deberían aparecer y desaparecer uno por uno). Para resolver este problema utilizo 2 CALayer separados porque por alguna razón en una capa 2 opaque las animaciones en capas múltiples son glitched.

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]; 
    } 
} 

Y al final, podemos obtener la secuencia de animación adecuada right animation

1

El punto es nombre de la 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. Probé 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") 
Cuestiones relacionadas