David
David

Reputation: 211

Transition behavior using transitionFromView and transitionWithView

I am attempting to create a transition between two subviews (view1 and view2). When a button is pressed I want view1 (front) to flip and show view2 (back). I have tried both transitionFromView and transitionWithView. Each works - but each has a problem.

transitionFromView - flips the superview (the whole window view flips, not the subviews). When this flip happens - one subview is on the front of the superview before the flip, and the other subview is on the back of the flip - as it should be. But I don't want the superview to flip, just the subviews.

transitionWithView - flips only the subviews - but the 'to' view gets displayed before the transition happens.

Anyone have a suggestion?

-(IBAction) button1action:(id) sender {  

 if ([sender tag] == 0) {  

  [UIView transitionFromView:view2 toView:view1 duration:2.0   
  options:UIViewAnimationOptionTransitionFlipFromLeft   
  completion:nil];   
}  

 else {  
  [view1 removeFromSuperview];    
  [self.view addSubview:view2];  
  [UIView transitionWithView:view2   
    duration:2.0  
    options:UIViewAnimationOptionTransitionFlipFromRight +  
    UIViewAnimationOptionShowHideTransitionViews  
      animations:^{}   
     completion:nil];  
 }
}

Upvotes: 21

Views: 36835

Answers (7)

Hal
Hal

Reputation: 1145

Having run into the same problem I agree with Eric and Sam: either transitionWithView or transitionFromView will both do what you want as given above as long as you create a container view of the appropriate size that you wish to flip. Otherwise the whole window view will flip.

So if view1 is the subview you begin with and you want to flip to view2 then add

UIView *containerView = [[UIView alloc] initWithFrame:appropriateSize];
[containerView addSubview:view1];

And then the simplest way to animate is probably:

[UIView transitionFromView:view1 
                    toView:view2 
                  duration:2.0   
                   options:UIViewAnimationOptionTransitionFlipFromLeft   
                completion:nil];   

Upvotes: 5

Ahmed Onawale
Ahmed Onawale

Reputation: 4050

using transitionFromView, both front and back view should be inside another view(not the super view). this way it will not flip the whole screen.

> superview
>     another view
>        backview
>        frontview

UIView.transitionFromView(frontView, toView: backView, duration: 0.5, options: .TransitionFlipFromLeft | .ShowHideTransitionViews) { finished in

}

You might want to make the (another view) equal to the size of the frontView

Upvotes: 0

Ilker Baltaci
Ilker Baltaci

Reputation: 11779

Keep in mind that the container view requires a solid background color.It means anything else than clear color.This was my mistake and spent quite long time to figure it out.

Upvotes: 0

Rui Nunes
Rui Nunes

Reputation: 848

Here's my working solution stub, a simple thing that took 2 hours, damn: we got 1 button to flip things, a UIView called panel that holds the 2 views I want to swap with a flip animation.

-(void)viewDidLoad{
    [super viewDidLoad];
    UIButton *btnFlip = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    btnFlip.frame = CGRectMake(10, 10, 50, 30);
    [btnFlip setTitle:@"flip" forState:UIControlStateNormal];
    [btnFlip addTarget:self action:@selector(flip) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btnFlip];

    panel = [[UIView alloc] initWithFrame:CGRectMake(10, 40, 300,300)];
    panel.backgroundColor = [UIColor darkGrayColor];
    [self.view addSubview:panel];

    panelBack = [[UIView alloc] initWithFrame:CGRectMake(10, 40, 280, 200)];
    panelBack.tag = 1;
    panelBack.backgroundColor = [UIColor brownColor];
    [panel addSubview:panelBack];

    panelFront = [[UIView alloc] initWithFrame:CGRectMake(10, 40, 280, 200)];
    panelFront.tag = 2;
    panelFront.backgroundColor = [UIColor whiteColor];
    [panel addSubview:panelFront];

    displayingFront = TRUE;
}

-(void)flip{

    [UIView transitionWithView:panel 
    duration:0.5
    options:(displayingFront ? UIViewAnimationOptionTransitionFlipFromRight : UIViewAnimationOptionTransitionFlipFromLeft)
    animations:^{ 
        if (displayingFront) {
            //panelFront.hidden=TRUE;
            //panelBack.hidden = FALSE;
            [panelFront removeFromSuperview];
            [panel addSubview:panelBack];
        }else{
            //panelFront.hidden=FALSE;
            //panelBack.hidden = TRUE;
            [panelBack removeFromSuperview];
            [panel addSubview:panelFront];
        }
     }
     completion:^(BOOL finished){
         displayingFront = !displayingFront;
     }];
}

Upvotes: 7

harry
harry

Reputation: 338

I had the same requirement, and saw many approaches -- from using layers (which ends up very complicated if you just want to deal with a UIView) to suggestions that i needed a "container" to then transition between to sub-views. But if you just want to swithc something front to back, like flipping over a playing card or a game tile, i made a one line change:

(note: i have an array of UIViews (tiles[x][y]) in a grid (for a game). i have all my imagefilenames in database tables / arrays, which dynamically are loaded into the UIImages of the UIImageViews. The image for the "back" of a card or tile in a UIImage named "tileBackPicImageNM".

so my code that simply swapped the front image out for an image of the back was:

[tiles[indexX][indexY] setImage:[UIImage imageNamed:tileBackPicImageNM]];

which works fine.

but and now, to show a flipping action, it is:

[UIView transitionWithView:tiles[indexX][indexY] duration:0.3 options:UIViewAnimationOptionTransitionFlipFromLeft 
                    animations:^{  
                        [[indexX][indexY] setImage:[UIImage imageNamed:tileBackPicImageNM]];
                    }
                    completion:NULL];    

I experimented with different "duration" parameters -- subsequently made it a float that I set in the viewDidLoad routine. Faster than 0.3 is almost not visible, and a value of 1 or 2 is very slow...

This does not involve two sub-views, which is my case is a lot more useful since i didn't want to have an array of containers containing a hierarchy of views, etc... and on new levels etc i always reload the arrays anyway...

Upvotes: 1

Sam
Sam

Reputation: 27354

I have run into this exact same problem, and I agree with the earlier answer. It seems you must have a container view for animating a transition from one subview to another subview.

I'm using the transitionFromView approach. To have a background behind the animation, you will also need a superview with the background for the container view.

My code looks like:

    [UIView transitionFromView:view1
                        toView:view2
                      duration:0.5
                       options:UIViewAnimationOptionTransitionFlipFromRight |
                               UIViewAnimationOptionAllowUserInteraction    |
                               UIViewAnimationOptionBeginFromCurrentState
                    completion:nil];

Upvotes: 13

Erik B
Erik B

Reputation: 42554

You need to remove and add the subviews in the animation block. Also, I think that transitionWithView is supposed to take the super view as argument. I think what you need to do to get this right is to use a container view that is the same size as the views you want to flip.

This is copied from the documentation:

[UIView transitionWithView:containerView
       duration:0.2
       options:UIViewAnimationOptionTransitionFlipFromLeft
       animations:^{ [fromView removeFromSuperview]; [containerView addSubview:toView]; }
       completion:NULL];

Upvotes: 26

Related Questions