1
votes

I have a custom container UIViewController. The container contains two children UIViewControllers. I need to disable rotation for one of them.

Documentation states:

By default, rotation and appearance callbacks are automatically forwarded to children.

But -(BOOL)shouldAutorotate got never called for children.

How to disable rotation for child view controller in iOS 8?

3

3 Answers

3
votes

Your question could do with some more detail to be certain what you are trying to achieve. Here's an answer, but given the question is a little vague I might have made some wrong assumptions.

The method you refer to, -shouldAutoRotate, only applies to the top-level viewController's view. The subviews do not rotate, relatively speaking. But they may adjust themselves according to the new layout.

What you probably do want to do is counterrotate the 'static' view, so that it maintains a fixed aspect with respect to the screen.

The doc you are quoting from is referring to these methods (pre-ios8)

– willRotateToInterfaceOrientation:duration:
– didRotateFromInterfaceOrientation:

in ios8 they are deprecated and replaced with

- viewWillTransitionToSize:withTransitionCoordinator:

If you use this method, you will have to check the orientation from [UIDevice currentDevice] and make the counter-rotation adjustment (which would be a rotation transform) to suit.

If this doesn't work out for you, it is always possible to make a custom view and have it (or the viewController) register for device rotation notifications. For this you would send beginGeneratingDeviceOrientationNotifications to [UIDevice currentDevice] and then register for those notifications with the notification centre:

  [[NSNotificationCenter defaultCenter] 
           addObserver:self 
              selector:@selector(deviceOrientationDidChange) 
                  name:UIDeviceOrientationDidChangeNotification object:nil];

edit

"what about frame?"

What about frame? It's not relevant here. You will be applying a rotation transform to your 'non-rotating' view. Apple advises never to get or set the frame property after transforms have been applied, as the numbers no longer make sense. You can set bounds and centre properties instead, or - possibly better - use autolayout constraints or autoresizing mask to get your result.

edit2

Here is an (animating) example using viewWillTransitionToSize:

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {

     UIDeviceOrientation deviceOrientation = 
       [UIDevice currentDevice].orientation;
     CGAffineTransform transform = 
      [self transformForOrientation:deviceOrientation];
     CGPoint center = 
        [self centerForOrientation:deviceOrientation];
     [UIView animateWithDuration:0.2 animations:^{
        self.rotatingView.center = center;
        self.rotatingView.transform = transform;
}];   
}

where transformForOrientation will return the appropriate rotation transform, and centerForOrientation will return a centre derived from the original unrotated view's centre coordinates.

Using viewWillTransition enables you to take control of the rotation before the interface has rotated to the new device orientation. At this point UIDeviceOrientation will give you the correct destination orientation, while UIInterfaceOrientation will still return the pre-rotated aspect. If you need really tight coordination between animations, you can use a UIViewControllerTransitionCoordinator object.

1
votes

In the view controller

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}
1
votes

I don't think you can. When the application queries a viewController for supported orientations it only polls one of them and then makes a transform on the entire window. The best I can suggest is a affine transform on the container view of the viewController in question in order to reverse/compensate the rotation.