首页 文章

CoreAnimation - 不透明淡入淡出动画不起作用

提问于
浏览
20

我正在尝试创建一个相当简单的CoreAnimation,用于 AVComposition . 我的目标是创建一个 CALayer ,它通过各种子层淡入淡出 Headers ,然后淡出图像 . 幻灯片,基本上 . 这是使用 AVAssetWriter 导出到.mov .

在WWDC 2011 AVEditDemo的帮助下,我已经能够获得一个 Headers 和图像 . 问题是它们同时都在屏幕上!

我创建了每个图层的不透明度为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秒 . 就像 Headers 一样,它们的淡出动画效果很好 .

任何帮助将不胜感激!

干杯!

EDIT

答案都很有帮助,但最终我发现只有一个动画可以添加到 CALayer . 淡出动画正在运行,因为它是最后添加的动画 .

然后我尝试了CAAnimationGroup,但这不起作用,因为我修改了相同的键值路径 .

所以我意识到 CAKeyframeAnimation 是最好的 . 只有我逐渐消失 . 我've tried various fillMode' s,改变了持续时间等等 . 不能让它工作!!

这是我的代码:

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

11 回答

  • 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];
    
  • 1

    男人,这么多复杂的答案 . 最简单的方法就是添加自动反转 . 瞧 .

    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"];
    
  • 1

    这对我有用:

    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
    
  • 2

    尝试:

    fadeInAnimation.beginTime = CACurrentMediaTime()+1.0;
    
  • 25

    我想你正在寻找 timeOffset ,而不是 beginTime ......

  • 1

    问题的核心是没有理解CAKeyframeAnimation的keyTimes属性 . 这个问题澄清了一切,让我走上了正确的道路:

    What kind of value is keyTime in an CAKeyFrameAnimation?

  • 1

    借用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];
    
  • 1

    LenK的答案对我来说非常合适 . 如果有人有兴趣,我会为Obj-C重写(注意我也略微更改了淡入的关键帧):

    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;
    
  • 1

    重点是关键名称 . 您必须设置不透明度键 .

    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")
    
  • 0

    另一种方法是使用CAAnimationGroup . CAKeyframeAnimation也适用于UI . 此代码在UI中可以很好地实时显示动画 . 但 will not work at allAVVideoCompositionCoreAnimationTool - 如果需要,请向下滚动 . 它不是代码准备好复制粘贴,但你可以得到这个想法 . 此外,您还可以向该组添加其他动画:

    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图像( Headers 应该一个接一个地出现和消失) . 为了解决这个问题,我使用了2个单独的 CALayer ,因为出于某种原因,在一个图层2上多个图层上的动画都是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];
        }
    }
    

    最后,我们可以获得适当的动画序列
    right animation

  • 28

    看看我的回答https://stackoverflow.com/a/44204846/667483

    总结:要使用 beginTime ,您应该在动画对象上将fillMode设置为 kCAFillModeBackwards .

相关问题