6

I am adding some basic animation to a card game I'm working on. (My first iPhone app.)

I am creating a custom UIView class "AnimationContainer", which flips from image1 to image2, while moving from rect1 to rect2. My ultimate intention is to have up to four of these containers doing their transitions simultaneously.

The problem I'm having is that the animation isn't showing image1... so only the last half of the flip transition appears.

However, if I reset the animation first by touching Reset, then everything works perfectly. In other words, if I press Flip again and again, I only get half the transition... but if I press Reset first, then everything works perfectly for one flip.

So, how can I get the animation to reset itself correctly?

Below is the code, a screenshot, and here's a link to the complete: Project Zip File 700k.

alt text

- (void)displayWithImage1 {     //RESET button calls this
    self.frame = rect1;
    [image2 removeFromSuperview];
    [self addSubview:image1];
    [self setNeedsDisplay]; //no help: doesn't force an update before animation
}

- (void)runTheAnimation {     //FLIP button calls this
    [self displayWithImage1]; //<---this is what the reset button calls
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationTransition:transition forView:self cache:NO];
    self.frame = rect2;
    [image1 removeFromSuperview];
    [self addSubview:image2];
    [UIView commitAnimations];
}

Thanks!

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Rob
  • 1,288
  • 13
  • 22
  • I've come up with a half-ugly workaround. I added a "dummy" animation and made my class a delegate for its setAnimationDidStopSelector. The dummy animation has a duration of 0.0 and just moves the view to rect1. When the dummy's stop selector is called, there I do the "real" animated flip code from above. Fully functional, and it looks like at least 4 can be running simultaneously. Yay, me. LOL – Rob Sep 21 '09 at 21:16
  • 1
    Turns out that the workaround can produce up to a half second of delay, so I'm starting a bounty. There must be a way to send a container view two images and have it flip from one to the next all in one transition. – Rob Oct 01 '09 at 02:22

1 Answers1

12

You need a drawing loop to pass in order to redraw the view before performing the animation. This code is an example of "draw this, and when the next event loop comes around, do this other thing." It's not uncommon to do this in UI code. Your first work-around is attempting the same thing, but in a much more complicated way.

- (void)_runTheAnimation {
    // Moved here from -runTheAnimation
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationTransition:transition forView:self cache:NO];
    self.frame = rect2;
    [image1 removeFromSuperview];
    [self addSubview:image2];
    [UIView commitAnimations];
}

- (void)runTheAnimation {     //FLIP button calls this
    [self displayWithImage1];
    [self performSelector:@selector(_runTheAnimation) withObject:nil afterDelay:0.0];
}
Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • 1
    Awesome! Thank you so much. I wasn't at all clear that selectors didn't execute immediately. Everything's working great now. The 200 rep bounty was a small price to pay. I've spent 10 hours messing with this. – Rob Oct 01 '09 at 03:21
  • 1
    Selectors are sent immediately if asked to (-peformSelector:) The method above is -performSelector:withObject:afterDelay:, which schedules on the runloop for the selector to be sent at some point in the future. A delay of 0 effectively means "the next time the run loop iterates." Selectors themselves just describe a message to pass to an object. The act of passing that message is done by the performSelector... methods. – Rob Napier Oct 01 '09 at 11:50
  • 1
    Cool, I think I understand. Still getting up to speed on Cocoa, Objective-C and all things iPhone... but I'm learning faster now. Thanks again. – Rob Oct 01 '09 at 15:26