Search code examples
iosuiviewanimationtransition

UIView setAnimationTransition only working sometimes but not always?


I'm writing a little card game where 4 cards are dealt to the screen and the user can tap each card to reveal (and again to hide) it.

Each card-front and card-back are stored in image views. A UIButton catches the user tap and should flip the card over.

I've added front and back of the card as subviews to a container view and I use the method UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight for the animation.

Please see the code below, I've removed the handling of the 4 different cards in the methods below for the sake of simplification & readability. Also I've replaced some array/filename-juggling for the cards with static image-names for front and back here.

The strange thing with this code now is the sometimes it works as expected 10 times in a row (i.e. the flipping animation is shown) but sometimes no animation is shown at all (i.e. the other card side is shown but without the flipping.). Then it's the other way round: Sometimes the card is shown without any animation for 7 or 8 times then suddenly the flipping-animation is shown. It's driving me nuts as I can't see the reason for this strange behaviour. Do you have any idea? I'm building for iOS 8 to iOS 10.

From the .h file:

@interface GameViewController : UIViewController 
{
    UIImageView             *cardback1;
    UIImageView             *cardfront1;
    UIView                  *containerView;
    BOOL                    c1Flipped;
    // much more...
}

And from the .m file:

-(void)flipCardButtonClicked:(id)sender
{
    containerView = [[UIView alloc] initWithFrame: CGRectMake(25,420,220,300)];
    [self.view addSubview:containerView];       

    c1Flipped = !c1Flipped;

    cardback1 = [[UIImageView alloc] initWithFrame: CGRectMake(0,0,220,300)];
    cardfront1 = [[UIImageView alloc] initWithFrame: CGRectMake(0,0,220,300)];

    if (c1Flipped)       
    {
        cardback1.image = [UIImage imageNamed:@"backside.png"];
        cardfront1.image = [UIImage imageNamed:@"frontside.png"];
    }
    else 
    {
        cardback1.image = [UIImage imageNamed:@"frontside.png"];
        cardfront1.image = [UIImage imageNamed:@"backside.png"];
    }

    [containerView addSubview:cardfront1];
    [containerView addSubview:cardback1];
    [cardfront1 release];
    [cardback1 release];

    [self performSelector:@selector(flipSingleCard) withObject:nil afterDelay:0.0];
}

-(void)flipSingleCard
{
    [containerView.layer removeAllAnimations]; 
    [UIView beginAnimations:@"cardFlipping" context:self];  
    [UIView setAnimationBeginsFromCurrentState:YES];   
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(flipDidStop:finished:context:)];
    [UIView setAnimationDuration:0.5];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:containerView cache:YES];
    [containerView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    [UIView commitAnimations];
}

-(void)flipDidStop:(NSString*)animationID finished:(BOOL)finished context:(void *)context 
{
    [containerView removeFromSuperview];
    [containerView release];
}

Solution

  • My guess is that [self performSelector:@selector(flipSingleCard) withObject:nil afterDelay:0.0]; is the culprit. Seems like this could be a timing issue. Have you tried adding an actual delay to this? Say...0.1? I believe that doing this could fix this, OR just simply calling the method directly instead of using performSelector.