J'essaie de créer une CoreAnimation assez simple à utiliser dans un AVComposition
. Mon objectif est de créer une variable CALayer
qui, par l’intermédiaire de différentes sous-couches, permet d’affiner et de masquer un titre, puis de masquer les images. Un diaporama, fondamentalement. Ceci est exporté vers un .mov en utilisant AVAssetWriter
.
Avec l'aide de AVEditDemo WWDC 2011, j'ai pu faire apparaître un titre et des images. Le problème est qu'ils sont tous à l'écran en même temps!
J'ai créé chaque calque avec une opacité de 0.0. J'ai ensuite ajouté un CABasicAnimation
pour les atténuer de 0.0 à 1.0, en utilisant le code suivant:
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];
Le problème semble être la propriété 'beginTime'. Le "1.0" est censé être un délai, il commence donc 1 seconde après le début de l'animation. Cependant, il apparaît tout de suite à l'écran. Une animation en fondu
L'inverse de ce code, pour le fondu sortant, change simplement les valeurs fromValue à 1.0 et toValue à 0.0. Il a un temps initial de 4.0 et fonctionne parfaitement.
J'utilise les éléments suivants pour créer le 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;
Les animations de fondu d’image ont un début d’après 5 secondes. Comme le titre, leurs animations en fondu fonctionnent bien.
Toute aide serait grandement appréciée!
À votre santé!
MODIFIER
Les réponses étaient toutes utiles, mais j'ai finalement découvert qu'une seule animation pouvait être ajoutée à un CALayer
. L'animation de fondu fonctionnait, car c'était la dernière ajoutée.
J'ai ensuite essayé un groupe CAAnimation, mais cela ne fonctionnait pas car je modifiais le même chemin de valeur de clé.
J'ai donc compris qu'un CAKeyframeAnimation
est le meilleur pour cela. Seulement, j'ai aussi des difficultés avec ça! Le code est en train de disparaître, mais il ne disparaît pas. J'ai essayé divers fillMode, changé la durée, etc. Je ne peux pas le faire fonctionner!
Voici mon code:
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];
Je suis confronté au même problème et le problème est le suivant: une couche ne peut pas contenir de fondu en entrée et en sortie. Vous pouvez donc ajouter l’autre animation au calque parent comme je l’ai fait.
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];
Homme, tellement de réponses compliquées. Le moyen le plus simple est d’ajouter une fonction 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"];
Cela fonctionne pour moi:
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
Le point est le nom de la clé. Vous devez définir la clé d'opacité.
layer.add(animation, forKey: nil) // Not Working
layer.add(animation, forKey: "opacity") // Working
Vérifiez l'exemple de code. J'ai testé dans 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")
La méthode alternative consiste à utiliser CAAnimationGroup. CAKeyframeAnimation fonctionne également très bien pour l'interface utilisateur. Ce code fonctionne bien dans l'interface utilisateur pour l'animation d'une émission en temps réel. Mais ne fonctionnera pas du tout dans AVVideoCompositionCoreAnimationTool
- veuillez faire défiler vers le bas si vous en avez besoin. Ce n'est pas un code prêt à être copié-collé mais vous pouvez en avoir l'idée. En outre, vous pouvez ajouter des animations supplémentaires au groupe:
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];
}
Voici une petite note sur l'animation sur les calques pour AVVideoCompositionCoreAnimationTool
. Vous pouvez voir l’image gif correspondante (les titres doivent apparaître et disparaître un à un). Pour résoudre ce problème, j'utilise 2 variables CALayer
car, pour une raison quelconque, sur un calque 2, des animations opaque
sur plusieurs calques sont enchevêtrées.
// 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];
}
}
Et à la fin, nous pouvons obtenir une séquence d'animation appropriée
Essayer:
fadeInAnimation.beginTime = CACurrentMediaTime()+1.0;
Je pense que vous cherchez timeOffset
, pas beginTime
...
Le cœur du problème ne comprenait pas la propriété keyTimes d'un fichier CAKeyframeAnimation. Cette question a tout clarifié et m'a mis dans la bonne voie:
Quel type de valeur est keyTime dans un CAKeyFrameAnimation?
Emprunter du lien mentionné par gamblor87 et ajouter mes commentaires comme explication.
//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];
LenK la réponse a parfaitement fonctionné pour moi. Si quelqu'un est intéressé, j'ai ré-écrit pour Obj-C (note j'ai aussi légèrement changé les images clés en fondu en entrée):
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;
Regardez ma réponse https://stackoverflow.com/a/44204846/667483
En résumé: pour utiliser beginTime
, vous devez définir fillMode sur kCAFillModeBackwards
sur votre objet d'animation.