14

I'm trying to create an animation that would look like 2 french doors (or 2 hatch doors) opening towards the user.

I tried using the built in UIViewAnimationOptionTransitionFlipFromRight transition, but the origin of the transition seems to be the center of the UIImageView rather than the left edge. Basically I have 2 UIImageViews that each fill have the screen. I would like the animation to look like the UIImageViews are lifting from the center of the screen to the edges.

[UIView transitionWithView:leftView
                  duration:1.0
                   options:UIViewAnimationOptionTransitionFlipFromRight                           
                animations:^ { leftView.alpha = 0; }
                completion:^(BOOL finished) {
                    [leftView removeFromSuperview]; 
                }];

Has anyone done something like this before? Any help would be awesome!

UPDATE: Working code thanks to Nick Lockwood

leftView.layer.anchorPoint = CGPointMake(0, 0.5); // hinge around the left edge
leftView.frame = CGRectMake(0, 0, 160, 460); //reset view position

rightView.layer.anchorPoint = CGPointMake(1.0, 0.5); //hinge around the right edge
rightView.frame = CGRectMake(160, 0, 160, 460); //reset view position

[UIView animateWithDuration:0.75 animations:^{
    CATransform3D leftTransform = CATransform3DIdentity;
    leftTransform.m34 = -1.0f/500; //dark magic to set the 3D perspective
    leftTransform = CATransform3DRotate(leftTransform, -M_PI_2, 0, 1, 0);
    leftView.layer.transform = leftTransform;

    CATransform3D rightTransform = CATransform3DIdentity;
    rightTransform.m34 = -1.0f/500; //dark magic to set the 3D perspective
    rightTransform = CATransform3DRotate(rightTransform, M_PI_2, 0, 1, 0);
    rightView.layer.transform = rightTransform;
}];
wes
  • 1,643
  • 2
  • 15
  • 12

1 Answers1

26

First add the QuartzCore library to your project and #import <QuartzCore/QuartzCore.h>

Every view has a layer property with sub-properties that are animatable. This is where you'll find all the really cool stuff when it comes to animation capabilities (I suggest reading up on the CALayer class properties you can set - it will blow your mind - dynamic soft drop shadows on any view?)

Anyway, back on topic. To rotate your doors open in 3D, first position them as if they were closed, so with each door filling half the screen.

Now set their view.layer.anchorPoint properties as follows

leftDoorView.layer.anchorPoint = CGPoint(0, 0.5); // hinge around the left edge
rightDoorView.layer.anchorPoint = CGPoint(1.0, 0.5); // hinge around the right edge

Now apply the following animation

[UIView animateWithDuration:0.5 animations:^{
   CATransform3D leftTransform = CATransform3DIdentity;
   leftTransform.m34 = -1.0f/500; //dark magic to set the 3D perspective
   leftTransform = CATransform3DRotate(leftTransform, M_PI_2, 0, 1, 0); //rotate 90 degrees about the Y axis
   leftDoorView.layer.transform = leftTransform;
   //do the same thing but mirrored for the right door, that probably just means using -M_PI_2 for the angle. If you don't know what PI is, Google "radians"
}];

And that should do it.

DISCLAIMER: I've not actually tested this, so the angles may be backwards, and the perspective may be screwy, etc. but it should be a good start at least.

UPDATE: Curiosity got the better of me. Here is fully working code (this assumes that the left and right doors are laid out in the closed position in the nib file):

- (void)viewDidLoad
{
    [super viewDidLoad];

    leftDoorView.layer.anchorPoint = CGPointMake(0, 0.5); // hinge around the left edge
    leftDoorView.center = CGPointMake(0.0, self.view.bounds.size.height/2.0); //compensate for anchor offset
    rightDoorView.layer.anchorPoint = CGPointMake(1.0, 0.5); // hinge around the right edge
    rightDoorView.center = CGPointMake(self.view.bounds.size.width,self.view.bounds.size.height/2.0); //compensate for anchor offset
}

- (IBAction)open
{
    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = -1.0f/500;
    leftDoorView.layer.transform = transform;
    rightDoorView.layer.transform = transform;

    [UIView animateWithDuration:0.5 animations:^{

        leftDoorView.layer.transform = CATransform3DRotate(transform, M_PI_2, 0, 1, 0);
        rightDoorView.layer.transform = CATransform3DRotate(transform, -M_PI_2, 0, 1, 0);
    }];
}

- (IBAction)close
{
    [UIView animateWithDuration:0.5 animations:^{

        CATransform3D transform = CATransform3DIdentity;
        transform.m34 = -1.0f/500;
        leftDoorView.layer.transform = transform;
        rightDoorView.layer.transform = transform;
    }];
}
Nick Lockwood
  • 40,865
  • 11
  • 112
  • 103
  • 1
    "dark magic" sounded better than "I don't feel like explaining matrices right now" ;-) – Nick Lockwood Feb 04 '12 at 01:54
  • 4
    Actually, I should have said "no one can be told what The Matrix is..." – Nick Lockwood Feb 04 '12 at 01:56
  • Awesome start thanks. I'm looking into this more. In the meantime, there's an error with the CATransform3DMakeRotation call which only take 4 args. I removed the '0' at the end and changed the first param to leftTransform.m34. Does that sound reasonable? It creates a strange instant transformation without the animation. – wes Feb 04 '12 at 01:56
  • Ahh OK. I think the method is actually CATransform3DRotate, right. I still don't see any animation happening, but I'll keep digging. – wes Feb 04 '12 at 02:02
  • I think I got it. I have the left door working. Should I post my working code under my question? (and then give you credit of course)! You're a lifesaver – wes Feb 04 '12 at 02:12
  • 1
    Beat you to it! Please post yours anyway - will be interesting to compare and contrast. – Nick Lockwood Feb 04 '12 at 02:31