使用CAAnimationGroup进行序列动画

时间:2013-07-20 16:45:38

标签: ios objective-c cocoa-touch cocoa core-animation

我正在尝试制作一系列动画,我在CAAnimationGroup找到了正确的类来实现该对象。在实践中,我添加了一个视图不同的子视图,我想用弹跳效果动画他们的条目,事实是我想看到他们的动画发生在前一个完成后。我知道我可以设置代理,但我认为CAAnimationGroup是正确的选择。
后来我发现组动画只能属于一个图层,但我需要它在屏幕上的不同图层上。当然在托管层上不起作用。 一些建议?

- (void) didMoveToSuperview {
    [super didMoveToSuperview];
    float startTime = 0;
    NSMutableArray * animArray = @[].mutableCopy;
    for (int i = 1; i<=_score; i++) {
        NSData *archivedData = [NSKeyedArchiver archivedDataWithRootObject: self.greenLeaf];
        UIImageView * greenLeafImageView = [NSKeyedUnarchiver unarchiveObjectWithData: archivedData];
        greenLeafImageView.image = [UIImage imageNamed:@"greenLeaf"];
        CGPoint leafCenter =  calculatePointCoordinateWithRadiusAndRotation(63, -(M_PI/11 * i) - M_PI_2);
        greenLeafImageView.center = CGPointApplyAffineTransform(leafCenter, CGAffineTransformMakeTranslation(self.bounds.size.width/2, self.bounds.size.height));
        [self addSubview:greenLeafImageView];

        //Animation creation
        CAKeyframeAnimation *bounceAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
        greenLeafImageView.layer.transform = CATransform3DIdentity;
        bounceAnimation.values = @[
                                  [NSNumber numberWithFloat:0.5],
                                  [NSNumber numberWithFloat:1.1],
                                  [NSNumber numberWithFloat:0.8],
                                  [NSNumber numberWithFloat:1.0]
                                  ];

        bounceAnimation.duration = 2;
        bounceAnimation.beginTime = startTime;
        startTime += bounceAnimation.duration;

        [animArray addObject:bounceAnimation];
        //[greenLeafImageView.layer addAnimation:bounceAnimation forKey:nil];


    }
    // Rotation animation
    [UIView animateWithDuration:1 animations:^{
        self.arrow.transform = CGAffineTransformMakeRotation(M_PI/11 * _score);
    }];
    CAAnimationGroup * group = [CAAnimationGroup animation];
    group.animations = animArray;
    group.duration = [[ animArray valueForKeyPath:@"@sum.duration"] floatValue];
    [self.layer addAnimation:group forKey:nil];
}

2 个答案:

答案 0 :(得分:23)

CAAnimationGroup用于将多个CAAnimation子类堆叠在一起形成动画,例如,一个动画可以执行缩放,另一个动画可以移动它,而第三个可以旋转它,它不是用于管理多个图层,而是用于多个叠加动画。

尽管如此,我认为解决问题的最简单方法是将每个CAAnimation beginTime等效项分配给所有先前项目的持续时间总和,以说明:

for i in 0 ..< 20
{
    let view : UIView = // Obtain/create the view...;
    let bounce = CAKeyframeAnimation(keyPath: "transform.scale")

    bounce.duration  = 0.5;
    bounce.beginTime = CACurrentMediaTime() + bounce.duration * CFTimeInterval(i);

    // ...

    view.layer.addAnimation(bounce, forKey:"anim.bounce")
}

请注意,每个人都获得duration * iCACurrentMediaTime()在使用beginTime属性时是必需的(它基本上是“现在”的高精度时间戳,用于动画)。整行可以解释为now + duration * i

必须注意,如果将CAAnimation添加到CAAnimationGroup,则其beginTime会相对于群组的开始时间,因此值为5.0在动画上,整个小组开始后5.0秒。在这种情况下,您不使用CACurrentMediaTime()

答案 1 :(得分:2)

如果您查看the documentation,则会注意到CAAnimationGroup继承自CAAnimation,而CAAnimation只能分配给CALayer。它的目的是让您可以轻松创建和管理您希望同时应用于CALayer的多个动画,而不是管理多个CALayer对象的管理器动画。

为了处理不同CALayerUIView个对象之间不同动画的排序,我使用的一种技术是为每个对象/动画创建一个NSOperation,然后将它们放入{ {1}}管理排序。这有点复杂,因为您必须使用动画完成回调来告诉NSOperationQueue它已完成,但如果您编写了一个NSOperation的良好动画管理子类,它可以相当方便并允许您创建复杂的排序路径。实现排序目标的低租金方式是在NSOperation对象上设置beginTime属性(来自它CAAnimation协议的采用),以便获得时间你想要的。

话虽如此,我将指出一些我编写的代码和开源代码,以解决您描述的完全相同的用例。您可能会发现on github here(包含相同的代码)。我将添加以下注释:

  • 我的动画管理代码允许您通过识别图像更改的顺序和时间,比例变化,位置变化等来定义您的动画。实际上,在plist文件中调整动画非常方便和清晰,而不是在代码中(这就是我写这个的原因)。
  • 如果不希望用户与您创建的子视图进行交互,那么创建作为子图层添加到托管视图图层的图层对象实际上会更好(更少开销)。