views:

112

answers:

1

I made a bunch of little individual pictures, each with a separate CALayer, and they're supposed to fade in and out asynchronously at different rates. Each has a background sublayer and a fill sublayer. A timer runs in the background to animate each one individually at specific moments. For the current behavior of the program, rather than animating each individual one, it animates the whole screen around it instead. Could you please help me make it so that it only animates one image at a time?

EDIT: I should have been clearer. Timing isn't the problem. Before I switched to CoreAnimation, these images animated correctly at the appropriate times. But the main issue here is that when I tell one image to animate, the whole screen, including background part of the screen outside of all of the images, gets animated.

The following code segment is for creating the layered structure in the UIView code. Self refers to the main UIView. The return value is used to set a CALayer member variable for a class representing one of these little images on the screen.

- (CALayer *) createImageLayer:(CGPoint)orig Center:(CGPoint)pos {
    CALayer *parentLayer = [self layer];
    CALayer *childLayer1 = [CALayer layer];
    childLayer1.bounds = CGRectMake(0, 0, 40.0f, 40.0f);
    childLayer1.position = pos;
    CALayer *childLayer2 = [CALayer layer];
    childLayer2.bounds = CGRectMake(0, 0, 40.0f, 40.0f);
    childLayer2.position = pos;

    float components[4] = {1.0, 1.0, 1.0, 1.0};

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGColorRef whiteColor = CGColorCreate( colorSpace, components);

    childLayer1.backgroundColor = whiteColor;
    childLayer2.backgroundColor = whiteColor;

    UIImage *childImage = [UIImage imageNamed:@"back.png"];
    UIImage *childImage2 = [UIImage imageNamed:@"fill.png"];

    CGImageRef imageRef = [childImage CGImage];
    CGImageRef imageRef2 = [childImage2 CGImage];

    childLayer1.contents=(id)imageRef;
    childLayer2.contents=(id)imageRef2;

    [parentLayer addSublayer:childLayer1];
    [parentLayer addSublayer:childLayer2];

    CGColorSpaceRelease(colorSpace);
    CGColorRelease(whiteColor);

    return parentLayer;
}

Code to tell it to animate. The image object is told to add the animation to its layer member.

- (void) fadeAnimation:(ImageClass *)image {
    CABasicAnimation *theAnimation;

    theAnimation=[CABasicAnimation animationWithKeyPath:@"opacity"];
    theAnimation.duration=1.0; // fixed duration for now
    theAnimation.repeatCount=1;
    theAnimation.autoreverses=YES;
    theAnimation.fromValue=[NSNumber numberWithFloat:1.0];
    theAnimation.toValue=[NSNumber numberWithFloat:0.0];
    [image.myLayer addAnimation:theAnimation forKey:@"animateOpacity"];
}
A: 

First, your code could be condensed pretty significantly which would make it easier to read:

- (CALayer *) createImageLayer:(CGPoint)orig Center:(CGPoint)pos 
{    
    CALayer *childLayer1 = [CALayer layer];
    childLayer1.bounds = CGRectMake(0, 0, 40.0f, 40.0f);
    childLayer1.position = pos;

    CALayer *childLayer2 = [CALayer layer];
    childLayer2.bounds = CGRectMake(0, 0, 40.0f, 40.0f);
    childLayer2.position = pos;

    childLayer1.backgroundColor = [[UIColor whiteColor] CGColor];
    childLayer2.backgroundColor = [[UIColor whiteColor] CGColor];

    childLayer1.contents=(id)[[UIImage imageNamed:@"back.png"] CGImage];
    childLayer2.contents=(id)[[UIImage imageNamed:@"fill.png"] CGImage];

    [[self layer] addSublayer:childLayer1];
    [[self layer] addSublayer:childLayer2];

    return parentLayer;
}

Next, I would suggest that rather than creating a timer, you just use -performSelector:withObject:afterDelay. Then you can add all of your animations at once simply staggering the afterDelay parameter. Something like this:

int i = 0;
for (i = 0; i < 10; ++i)
{
    [self performSelector:@selector(fadeAnimation:) 
               withObject:images[i] 
               afterDelay:(CGFloat)i];
}

Where images is a C array of your ImageClass objects. Of course you wouldn't have to use a C array. You could use an NSArray, but you would still need a counter for your afterDelay parameter. This would stagger your animations to occur every one second. I'm not sure exactly what you want so I'm just showing this as an example.

There are other ways to do what you're asking for with Core Animation. You can look at animation grouping and the beginTime property, but I think the -peformSelector method I mentioned above is a path of lesser resistance.

Best regards

Matt Long
Thank you for your help. The main problem I've been getting is that when I think I'm telling each individual image to do the fade animation, like [self fadeAnimation:myImage], it instead does the animation to the whole screen but not to the image. Timing isn't really the problem for me, but I could try out your suggestion since that does seem more appropriate for my purposes than a timer.
William