【问题标题】:CoreAnimation - Opacity Fade In and Out Animation Not WorkingCoreAnimation - 不透明度淡入和淡出动画不起作用
【发布时间】:2012-01-03 01:50:13
【问题描述】:

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

在 WWDC 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;

动画中的图像淡入淡出的 beginTime 间隔为 5 秒。就像标题一样,它们的淡出动画效果很好。

任何帮助将不胜感激!

干杯!

编辑

答案都很有帮助,但最终我发现只能将一个动画添加到CALayer。淡出动画正在工作,因为它是最后一个添加的。

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

所以我意识到CAKeyframeAnimation 是最适合这个的。只有我对此也有一些困难!代码现在可以淡入淡出,但不会淡出。我尝试了各种填充模式,更改了持续时间等。无法使其工作!

这是我的代码:

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

【问题讨论】:

标签: ios core-animation avfoundation calayer cakeyframeanimation


【解决方案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

【讨论】:

  • 在 func 中的好答案 :)
【解决方案2】:

伙计,这么多复杂的答案。最简单的方法就是添加自动反转。瞧。

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

【讨论】:

  • 此解决方案在淡出完成后立即开始淡出。我猜 OP 希望标题淡入,保持可见,然后淡出。
  • 确实是最佳答案。我会为那些正在苦苦挣扎的人添加,您也可能想要添加 [yourView setWantsLayer:YES];在获取视图层之前。默认情况下,视图没有图层。
【解决方案3】:

重点是键名。您必须设置不透明度键。

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

【讨论】:

  • 添加:您可以在layer.add或CAKeyframeAnimation(keyPath: "opacity")中设置密钥
【解决方案4】:

借鉴gamblor87提到的链接并添加我的cmets作为解释。

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

【讨论】:

  • fadeInAndOut.beginTime = 1.0 不行,需要使用 CACurrentMediaTime() + 1;
【解决方案5】:

我遇到了同样的问题,问题是 - 一层不能包含淡入和淡出。 所以你可以像我一样将其他动画添加到父层

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

【讨论】:

  • 我永远不会想到这一点。谢谢@comonitos
  • @DavidJohnSmith 很高兴为您提供帮助!
  • 可能是由于 iOS 7 SDK 的 2013-14 更新或我做了不同的事情,但目前可以向一个 layer 添加 多个 动画,无需使用额外的层@comonitos
【解决方案6】:

另一种方法是使用 CAAnimationGroup。 CAKeyframeAnimation 也适用于 UI。此代码在 UI 中运行良好,可实时显示动画。但是在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 多层上的动画出现了故障。

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

最后,我们可以得到正确的动画序列

【讨论】:

    【解决方案7】:

    试试:

    fadeInAnimation.beginTime = CACurrentMediaTime()+1.0;
    

    【讨论】:

      【解决方案8】:

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

      What kind of value is keyTime in an CAKeyFrameAnimation?

      【讨论】:

        【解决方案9】:

        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;
        

        【讨论】:

        • 这对我来说效果很好,但您需要添加一行:fadeInAndOutAnimation.repeatCount = HUGE_VALF;。否则视图会淡出一次,再也不会出现。
        【解决方案10】:

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

        总而言之:要使用beginTime,您应该在动画对象上将fillMode 设置为kCAFillModeBackwards。

        【讨论】:

          猜你喜欢
          • 2018-11-06
          • 1970-01-01
          • 2019-09-24
          • 2018-06-18
          • 2012-09-25
          • 1970-01-01
          • 1970-01-01
          • 2020-12-06
          • 1970-01-01
          相关资源
          最近更新 更多