Search code examples
objective-ccocoa-touchanimationuiviewcontrolleruideviceorientation

Override the UIViewController's default animation on device rotation


I want to provide a custom animation when the device rotates, completely overriding the default one. What's the best way to achieve this?

BTW, the kind of animation I'm planning is:

a) When the device goes into landscape, have a new view slide from the top as if it was falling.

b) When the device goes back to portrait, that view should slide down and dissappear.


Solution

  • Best is subjective and dependent upon your application as a whole.

    One fairly straight-forward way of handling the rotation events is telling the system not to and handling them yourself. For your desired effect of what essentially amounts to sliding a (pre-rotated) view in from the side when the device is rotated to the side, this would seem appropriate.

    Here is a very basic sample of how to achieve such an effect.

    @implementation B_VCRot_ViewController // defined in .h as @interface B_VCRot_ViewController : UIViewController
    @synthesize sideways; // defined in .h as @property (strong, nonatomic) IBOutlet UIView *sideways;
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
    -(void)orientationChange:(NSNotification *)note{
        UIDeviceOrientation newOrientation = [[UIDevice currentDevice] orientation];
        CGSize sidewaysSize = self.sideways.frame.size;
        if (newOrientation == UIDeviceOrientationLandscapeLeft){
            [UIView animateWithDuration:1.0 animations:^{
                self.sideways.frame = CGRectMake(0, 0, sidewaysSize.width, sidewaysSize.height);
            }];
        }
        else {
            [UIView animateWithDuration:1.0 animations:^{
                self.sideways.frame = CGRectMake(self.view.bounds.size.width, 0, sidewaysSize.width, sidewaysSize.height);
            }];
        }
    }
    - (void)viewDidLoad{
        [super viewDidLoad];
        [self.view addSubview:sideways];
        self.sideways.transform = CGAffineTransformMakeRotation(M_PI_2); // Rotates the 'sideways' view 90deg to the right.
        CGSize sidewaysSize = self.sideways.frame.size;
        // Move 'sideways' offscreen to the right to be animated in on rotation.
        self.sideways.frame = CGRectMake(self.view.bounds.size.width, 0, sidewaysSize.width, sidewaysSize.height);
        // register for rotation notifications
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChange:) name:UIDeviceOrientationDidChangeNotification object:nil];
        // Do any additional setup after loading the view, typically from a nib.
    }
    @end
    

    What I have done here is added a UIView with a landscape orientation in the .xib and connected it to an IBOutlet named sideways. In viewDidLoad I add it as a subview, pre-rotate it, and move it offscreen. I also add self as an observer for the device rotation notifications (Remember to remove yourself later for that notification). And in shouldAutoRo.. I indicate that this VC only handles portrait.

    When the device rotates NSNotificationCenter calls orientationChange:. At that point if the device is rotated to the left, my sideways view will slide in from the right (which seems like it's sliding down).

    Obviously for both landscape orientations the code would be more complex. Also you would likely have to mess around with the animation timing to make it feel as if the second view is "falling"