21

This is an iPad project where I have a UIView with several subViews, and I am trying to animate one of this UIViews using [UIView transitionFromView:toView:duration:options:completion], but when I run this method the whole parent view gets flipped! This is the code I'm using:

UIView *secondView = [[UIView alloc] initWithFrame:CGRectMake(200, 200, 300, 300)];
[newView setBackgroundColor:[UIColor redColor]];
    [UIView transitionFromView:self.firstView.view toView:secondView duration:1.0 options:UIViewAnimationOptionTransitionFlipFromLeft completion:nil];

Any idea on how can I flip between this views without animating the whole parent view? Thanks!

DanMunoz
  • 936
  • 1
  • 8
  • 10

6 Answers6

71

this code may helps you:

put the two views you want to flip inside an unnamed view with the same size and link the IBOutlet UIView *newView,*oldView; to the views and put the new view on top

bool a = NO;

@implementation ViewController

- (IBAction)flip:(id)sender 
{
    if (a == NO) {
        [UIView transitionFromView:oldView toView:newView  
                  duration:1.0 
                  options:UIViewAnimationOptionTransitionFlipFromLeft 
                  completion:NULL];
        a = YES; // a = !a;
    }
    else {
        [UIView transitionFromView:newView toView:oldView  
                  duration:1.0 
                  options:UIViewAnimationOptionTransitionFlipFromLeft 
                  completion:NULL];
        a = NO; // a = !a;
    }
}
Floris497
  • 1,406
  • 12
  • 18
  • 5
    Thanks a lot! The solution was to use a container view. – DanMunoz Mar 06 '12 at 14:43
  • 1
    Thanks for this. I had a feeling this was the solution. I guess the transition is more of a trick, it does a flip animation on the parent view, and half way through swaps out the subviews you specify. Then again, most animations etc.. on iPhone are a trick :-) – Dermot Jul 28 '12 at 03:55
  • 2
    This worked for me. However, the views were getting dealloced during the flip. My solution was to make the reference strong. – Juan Haladjian Nov 16 '14 at 03:59
  • 1
    Floris497 a dictionary may helps you ;) – return true Aug 05 '15 at 20:40
  • @returntrue maybe, it what form would that help me? :P – Floris497 Aug 06 '15 at 09:14
  • This technique works for switching child view controllers in container views - now just the container view flips not the other views that are peers to the ones getting switched! – David H Jan 23 '16 at 22:42
  • If using with autolayout constraints, this transition removes one of the views from view hierarchy and breaks the constraints chain. Keep this in mind before implementing this function in case of applied constraints. – Ishaan Sejwal Jan 28 '17 at 11:38
  • @IshaanSejwal To prevent the view from being removed add the option `UIViewAnimationOptionShowHideTransitionViews` to the transition. By default `transitionFromView` removes the old view and adds the new view. However if the new view is already added to the parent view you can simply use the aforementioned option to hide the old view and show the new view. – Manuel Sep 08 '17 at 01:07
37

I had problems getting this to work also. I used the code written by Floris, but although it worked for the first "flip" the next flip started to go weird where the buttons and labels on the frontside UI View lost there positions.

I put the code below into place and it is working fine.

Couple of things to note:

  1. panelView is a UIView control on the ViewController that has two other UIViews nested inside it (subviews). The first one is called frontView, second one is called backView. (see picture below)

image of the view and subviews in IB

  1. I have a bool property called displayingFront on the class

(in my .h)

@property BOOL displayingFront;

in my .m

@synthesize displayingFront;

in my viewDidLoad method

self.displayingFront = YES;

This is the code in the .m that i have rigged up to the two buttons if front and back UIViews...

- (IBAction)flip:(id)sender
{
    [UIView transitionWithView:self.panelView
                      duration:1.0
                       options:(displayingFront ? UIViewAnimationOptionTransitionFlipFromRight :
                                UIViewAnimationOptionTransitionFlipFromLeft)
                    animations: ^{
                        if(displayingFront)
                        {
                            self.frontView.hidden = true;
                            self.backView.hidden = false;
                        }
                        else
                        {
                            self.frontView.hidden = false;
                            self.backView.hidden = true;
                        }
                    }

                    completion:^(BOOL finished) {
                        if (finished) {
                            displayingFront = !displayingFront;
                        }
                    }];
}
Steve Parker
  • 766
  • 6
  • 4
  • I think this is more clean than the answer – RonPelayo Feb 14 '14 at 05:28
  • The difference with this approach is that the animations occur after the flip...so the frontView is hidden and the backView displayed after the flip. The "transitionFromView" approach detailed above adds the view at the midpoint so by the time the flip has completed, the "toView" is already showing. – wuf810 Mar 20 '14 at 23:39
  • Thanks! This solved my problems with misplaced subviews of the transitioning views (labels). They were scattered across the screen. – Boris Nikolic Aug 25 '15 at 13:26
  • Wowww..!! Wonderful answer. Thanks. – iGatiTech Mar 05 '16 at 12:28
  • Great...It save my time. – Jagat Dave Mar 23 '16 at 05:22
3

Use a container view to hold your subviews, and make the container view the same size as your subview that you're trying to animate.

So, you can setup your views like this.

self.view-> "a container view" -> subviews

greenhorn
  • 1,097
  • 6
  • 10
2
**//flipping view continuously**  



 bool a = NO;


-(void)viewDidLoad
{



// THIS is the canvass holding the two views this view is flipping
 UIView *v=[[UIView alloc]initWithFrame:CGRectMake(40, 40, 150, 150)];

   v.backgroundColor=[UIColor clearColor];

    [self.view addSubview:v];

     [v addSubview:yourfirstview];
     [v addSubview:yoursecondview];

// calling the method

[NSTimer scheduledTimerWithTimeInterval:2.0
                                     target:self
                                   selector:@selector(flip)
                                   userInfo:nil
                                    repeats:YES];

}



//flipping view randomly

-(void)flip 

{

if (a == NO) 
{

[UIView transitionFromView:yourfirstview toView:yoursecondview duration:1.0 options:UIViewAnimationOptionTransitionFlipFromLeft completion:NULL];
        a = YES;
    }

else if(a==YES) 
{

[UIView transitionFromView:yoursecondview toView:yourfirstview duration:1.0 options:UIViewAnimationOptionTransitionFlipFromLeft completion:NULL];
     a = NO;
  }

}
shankar
  • 239
  • 3
  • 5
2

I fixed this problem by using old-school animations:

[UIView beginAnimations:@"Flip" context:nil];
[UIView setAnimationDuration:1];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:firstView cache:YES];

[self addSubview:secondView];

[UIView commitAnimations];

Additionally you can remove the firstView:

[firstView removeFromSuperview];
Calin Drule
  • 2,899
  • 1
  • 15
  • 12
2

I'd like to make an update of Steve Parker's answer in SWIFT 4:-

var displayBlankView:Bool = true

UIView.transition(with:flipView, duration:1.0, options:displayBlankView ? .transitionFlipFromLeft:.transitionFlipFromRight, animations:{
        if(self.displayBlankView){
            self.view1.isHidden=true
            self.view2.isHidden=false
        }else{
            self.view1.isHidden=false
            self.view2.isHidden=true
        }
    }, completion:{
        (finished: Bool) in
        self.displayBlankView = !self.displayBlankView;

    })
khusboo suhasini
  • 293
  • 2
  • 16