Question

I have a functioning page curl that works. The problem is the rotation of the iPad. The app runs in landscape only and supports l left and l right. If the iPad is 'landscape right' the curl happens in the bottom right as it should. If I rotate the iPad the view rotates as expected but now when I try the curl happens in the top left. I have added a notification to tell me when it rotates and try and change the animation subtype but no dice.

   -(IBAction)curlViewUp
{
    uiv_help.alpha = 1.0;

    [UIView animateWithDuration:1.0
                     animations:^{
                         CATransition *animation = [CATransition animation];
                         [animation setDelegate:self];
                         [animation setDuration:0.7];
                         [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
                         animation.type = @"pageCurl";
                         animation.subtype = curlDirection;
                         animation.fillMode = kCAFillModeForwards;
                         animation.endProgress = 0.20;
                         [animation setRemovedOnCompletion:NO];
                         [self.view.layer addAnimation:animation forKey:@"pageCurlAnimation"];
                         [self.view addSubview:uiv_help];
                         ;}
     ];
}

-(IBAction)curlViewDown
{
    uiv_help.alpha = 0.0;

    [UIView animateWithDuration:1.0
                     animations:^{
                         CATransition *animation = [CATransition animation];
                         [animation setDelegate:self];
                         [animation setDuration:0.7];
                         [animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]];
                         animation.type = @"pageUnCurl";
                         animation.subtype = curlDirection;
                         animation.fillMode = kCAFillModeForwards;
                         animation.startProgress = 0.80;
                         [animation setRemovedOnCompletion:YES];
                         [self.view.layer addAnimation:animation forKey:@"pageUnCurlAnimation"];
                         //[self.view removeFromSuperview];
                         [uiv_help removeFromSuperview];
                         ;}
     ];

}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft | interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}

-(void)checkRotation:(NSNotification*)notification
{
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
    if(orientation == UIInterfaceOrientationLandscapeLeft)
    {
        NSLog(@"UIInterfaceOrientationLandscapeLeft");

        curlDirection = @"fromRight";
    } else if (orientation == UIInterfaceOrientationLandscapeRight) {
        NSLog(@"UIInterfaceOrientationLandscapeRight");

        curlDirection = @"fromRight";
    }
}
Was it helpful?

Solution

Your pagecurl is not rotating with the device.

This is because it's view is not rotating with the device rotation..

This is because it's view is the topmost view in the view hierarchy.

I can't find the documentation for this anywhere (can someone else dig it out?), but it is nevertheless the case that the outermost view in the view hierarchy does not rotate. I guess that is because it is this view who's responsibility is to rotate everything else (or rather, this view to which some kind of rotation transform is applied).

This is a simple thing to verify, just log your view's frame and bounds and watch what happens on rotation.

Here we are in portait mode. I have set up a subview contained inside self.view, with the same dimensions.

self.view frame {{0, 20}, {768, 1004}}
self.view bounds {{0, 0}, {768, 1004}}
self.view center {384, 522}
--------
self.subview frame {{0, 0}, {768, 1004}}
self.subview bounds {{0, 0}, {768, 1004}}
self.subview center {384, 502}

Now lets rotate to landscape

self.view frame {{20, 0}, {748, 1024}}
self.view bounds {{0, 0}, {1024, 748}}
self.view center {394, 512}
--------
self.subview frame {{0, 0}, {1024, 748}}
self.subview bounds {{0, 0}, {1024, 748}}
self.subview center {512, 374}

you will see that the inner subview is correctly reporting width as 1024 and height as 748px. but the outer view has just gone weird. It's frame reports a width of 748 and a height of 1024 as if it is still portrait (with the addition of the statusbar 20px). But it's bounds tell us it is landscape.

We clearly don't want to rely on the geometric properties of a view that reports such strange results. I imagine that this is related to Apple's warning that you shouldn't reference a view's frame if it has been subject to any transform other than the identity transform.

The solution is to embed your pagecurling view in another outermost view.. Create a new view, call it self.subview (or whatever), and add it to your view hierarchy as the only child of self.view. Size it to the same rect as self.view. Operate on self.subview instead of self.view.

Change this line:

[self.view.layer addAnimation:animation forKey:@"pageCurlAnimation"];

to

[self.subview.layer addAnimation:animation forKey:@"pageCurlAnimation"];

and change this line:

[self.view.layer addAnimation:animation forKey:@"pageUnCurlAnimation"];

to:

[self.subview.layer addAnimation:animation forKey:@"pageUnCurlAnimation"];

Then your curls will operate as you expect, because you are applying them to a view that rotates as you expect it to.

You could achieve the same result without change your code, but embedding your viewController in a UINavigationViewController. In that case the NavViewController's view is the outermost view which does not rotate. So your self.view will rotate.

update

UIWindow* mWindow = [[UIApplication sharedApplication] keyWindow];
UIView *topView = [[mWindow subviews] lastObject];
NSLog("%@",topView);


topView <UILayoutContainerView: 0x71eb450; 
frame = (0 0; 748 1024); 
transform = [0, 1, -1, 0, 0, 0];     
autoresize = W+H; gestureRecognizers = <NSArray: 0x71f8a30>; 
layer = <CALayer: 0x71eb540>>

Note the transform.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top