使用CoreAnimation同步图像,文本和定位

时间:2012-03-04 22:21:49

标签: ios core-animation caanimation cabasicanimation cakeyframeanimation

我是一个有动画的初学者,并且已经尝试使用CoreAnimation几天了。如果这个问题没有意义,请随时警告我,但我正在努力实现以下目标。我有三个对象:

  • 一个应该是一个图像,根据给定的模式移动
  • 一个应该是交换两个图像的UIImage
  • 一个应该是内容更改的文本(CATextLayer?)

这三个动作应该同步进行。

作为一个例子,考虑一个显示正弦函数的程序,如在ECG中,在-1和+1之间振荡:第一个图像将根据当前值(-1,-0.9,-0.8, ... 0,+ 0.1,+ 0.2,... 1),交换图像的正值显示“+”,负值显示“ - ”,文本将在“正”和“负”之间交替显示。

我尝试过CAAnimationGroup,但我显然遗漏了一些东西。一些代码:

{
    // image that moves
    CALayer *img1 = [CALayer layer];
    img1.bounds = CGRectMake(0, 0, 20, 20);
    img1.position = CGPointMake(x1,y1);
    UIImage *img1Image = [UIImage imageNamed:@"image.png"];
    img1.contents = (id)img1Image.CGImage;

    // image that changes 
    CALayer *swap = [CALayer layer];
    swap.bounds = CGRectMake(0, 0, 30, 30);
    swap.position = CGPointMake(x2,y2);
    NSString* nameswap = @"img_swap_1.png"
    UIImage *swapImg = [UIImage imageNamed:nameswap];

    // text
    CATextLayer *text = [CATextLayer layer];
    text.bounds = CGRectMake(0, 0, 100, 100);
    text.position = CGPointMake(x3,y3);
    text.string = @"Text";


    // create animations
    CGFloat duration = 0.2;
    CGFloat totalDuration = 0.0;
    CGFloat start = 0;

    NSMutableArray* animarray = [[NSMutableArray alloc] init];
    NSMutableArray* swapanimarray = [[NSMutableArray alloc] init];
    NSMutableArray* textanimarray = [[NSMutableArray alloc] init];

    float prev_x = 0;
    float prev_y = 0;

    // I get my values for moving the object
    for (NSDictionary* event in self.events) {

            float actual_x = [[event valueForKey:@"x"] floatValue];
            float actual_y = [[event valueForKey:@"y"] floatValue];


            // image move animation
            CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];            
            CGPoint startPt = CGPointMake(prev_x,prev_y);
            CGPoint endPt = CGPointMake(actual_x, actual_y);
            anim.duration = duration;
            anim.fromValue = [NSValue valueWithCGPoint:startPt];
            anim.toValue = [NSValue valueWithCGPoint:endPt];
            anim.beginTime = start;
            anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];            
            [animarray addObject:anim];


            // image swap animation
                        CABasicAnimation *swapanim = [CABasicAnimation animationWithKeyPath:@"contents"];

            swapanim.duration = duration;
            swapanim.beginTime = start;

            NSString* swapnamefrom = [NSString stringWithFormat:@"%@.png", prev_name];
            NSString* swapnameto = [NSString stringWithFormat:@"%@.png", current_name];
            UIImage *swapFromImage = [UIImage imageNamed:swapnamefrom];
            UIImage *swapToImage = [UIImage imageNamed:swapnameto];
            swapanim.fromValue = (id)(swapFromImage.CGImage);
            swapanim.toValue = (id)(swapToImage.CGImage);
            swapanim.fillMode = kCAFillModeForwards;
            swapanim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];      
            [swapanimarray addObject:swapanim];

            //text animation
            CABasicAnimation *textanim = [CABasicAnimation animationWithKeyPath:@"contents"];            
            textanim.duration = duration;
            textanim.fromValue = @"Hey";
            textanim.toValue = @"Hello";
            textanim.beginTime = start;
            [textanimarray addObject:textanim];


            // final time settings
            prev_x = actual_x;
            prev_y = actual_y;
            start = start + duration;
            totalDuration = start + duration;

        }

    }


    CAAnimationGroup* group = [CAAnimationGroup animation];
    [group setDuration:totalDuration]; 
    group.removedOnCompletion = NO;
    group.fillMode = kCAFillModeForwards;
    [group setAnimations:animarray];

    CAAnimationGroup* swapgroup = [CAAnimationGroup animation];
    [swapgroup setDuration:totalDuration]; 
    swapgroup.removedOnCompletion = NO;
    swapgroup.fillMode = kCAFillModeForwards;
    [swapgroup setAnimations:swapanimarray];

    CAAnimationGroup* textgroup = [CAAnimationGroup animation];
    [textgroup setDuration:totalDuration]; 
    textgroup.removedOnCompletion = NO;
    textgroup.fillMode = kCAFillModeForwards;
    [textgroup setAnimations:textanimarray];

    [ball addAnimation:group forKey:@"position"];
    [swap addAnimation:flaggroup forKey:@"position"];
    [text addAnimation:textgroup forKey:@"contents"];

    [self.layer addSublayer:ball];
    [self.layer addSublayer:swap];
    [self.layer addSublayer:text];


}

现在......问题:

1)交换图像在每次交换时恢复为原始图像。所以,如果我交换A-> B,我看到它在预期的持续时间内从A到B,但后来又回到A.我已经在SO上读了很多关于这个的线程但是无法得到它工作

2)以定时方式更改文本图层的字符串...这可以通过此基础结构实现吗?基本上,我试图在第一个图像移动时立即改变文本和交换图像,如示例中所述。

3)设置CABasicAnimation的委托没有任何效果,尽管它适用于CAAnimationGroup:因此,您无法为每个动画管理像animationDidStop这样的事件,只针对整个组。有没有其他方法可以这样做?

4)从3)开始,是否有可能使用CAAnimationGroup拦截事件以创建停止/启动行为?我们假设我想要播放/停止按钮,并从我离开的地方恢复动画?

作为一个结论性的问题,我只想知道是否有人做了类似的事情,最重要的是,如果这种做事方式(使用CAAnimationGroup)实际上是要走的路,或者是否更好地使用CAKeyFrameAnimation或其他什么东西其他

1 个答案:

答案 0 :(得分:1)

我设法解决了这个问题,尽管有一些解决方法。

1)这里的诀窍是

removedOnCompletion = NO;
fillMode = kCAFillModeForwards;

需要分配给每个动画,而不是CAAnimationGroup。

2)这需要为CATextLayer确定单独的动画,并为“string”属性设置动画。在这种情况下,代码是正确的,除了“内容”键值应该是

[text addAnimation:textgroup forKey:@"contentAnimate"];

或者,请参阅第3点。回调操作方式允许更改label.text。

3)实现此目的的唯一方法是实际不使用CAAnimationGroup并设置CABasicAnimation序列。一般模式是:在函数中创建第一个CABasicAnimation,分配委托。在animationDidStop方法中,向创建CABasicAnimation的函数添加回调。这样,每个动画都将被创建。同时,这允许拦截和响应动画中的特定事件。

-(void)performNextAnimation:(int)index {
    // ... this gives for granted you have an object for #index ...
    NSDictionary* thisEvent = [self.events objectAtIndex:index];
    float prev_x = [thisEvent valueForKey:@"prev_x"];
    float prev_y = [thisEvent valueForKey:@"prev_x"];
    float actual_x = [thisEvent valueForKey:@"prev_x"];
    float actual_y = [thisEvent valueForKey:@"prev_x"];
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];            
    GPoint startPt = CGPointMake(prev_x,prev_y);
    CGPoint endPt = CGPointMake(actual_x, actual_y);
    anim.duration = 0.5;
    anim.fromValue = [NSValue valueWithCGPoint:startPt];
    anim.toValue = [NSValue valueWithCGPoint:endPt];
    anim.beginTime = start;
    [anim setDelegate:self];
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];            
    [object addAnimation:anim forKey:@"position"];
}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag {
    // ... your conditions go here ...
    // ... your actions go here ... 
    //     e.g. set label.text
    [self performNextAnimation];
}

4)从3开始,这在CAAnimationGroup中是不可能的。阅读文档,我会说CAAnimationGroup不打算用于每个事件代表一个时间步骤的序列(为此你需要使用CAKeyFrameAnimation或CABasicAnimation序列和回调函数,就像我做的那样)。 CAAnimationGroup适用于应该以全有或全无的方式执行的链接动画(类似于CATransaction)。