Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Child View Controller rotation methods not being called

Summary

I am attempting to add a child view controller to a parent view controller, and have the parent view controller inform the child view controller of rotation events. However, the rotation messages are not being forwarded to the child view controller (which is the default behavior). Why is this default behavior not occurring?

Environment: iOS 7, XCode 5, OSX 10.9

Details:

I am implementing a custom container view controller following instructions in the Apple Document: "Creating Custom Container View Controllers". I am attempting to establish a simple parent child relationship that forwards rotation events. The total hierarchy is exactly as pictured in the documentation figure 14-1 redrawn here:

ParentViewController --------> RootView
        |                       /   \
        |                      /     \
        ˅                     /       \
ChildViewController ---> ChildView     \ 
                                        \   
                                    OverLayView

I am accomplishing this using the code from the document Listing 4-1 in the parentViewController (unityViewController = childViewController, unityView = childView):

// In the ParentViewController    
// Called by the Application Delegate in application:didFinishLaunchingWithOptions:
- (void)addUnityViewController:(UIViewController *)unityViewController withUnityView:(UIView *)unityView
{
    [self addChildViewController:unityViewController]; // 1. Establish Child parent relationship

    unityView.frame = self.view.frame;                 // 2. Set the frame (explicitly or with constraints)
    [self.view addSubview:unityView];                  // 2.1 Add the subview AFTER you set the frame
    ... // add some view constraints here

    [self.view sendSubviewToBack:unityView];           // In the back, but not completely obstructed by any other views
    [unityViewController didMoveToParentViewController:self];// 3. Tell the child what happened
}

This code successfully displays the child view as a subview of the RootView with the OverlayView adding some functional buttons. However, when the device rotates, the parent view controller rotates its views successfully, but does not forward the rotation messages to the child view controller (unityViewController) resulting in an improperly displayed childView (unityView) in the rootView. According to "Creating Custom Container View Controllers" this should happen automatically:

Customizing Appearance and Rotation Callback Behavior: Once you add a child to a container, the container automatically forwards rotation and appearance callbacks to the child view controllers as soon as an event occurs that requires the message to be forwarded.

To ensure that this should be happening, I overrode the following methods:

// In the parent ViewController:
- (BOOL)shouldAutorotate
{
    return YES;
}

- (BOOL)shouldAutomaticallyForwardAppearanceMethods
{
    return YES;
}

- (BOOL)shouldAutomaticallyForwardRotationMethods
{
    return YES;
}

However, the willRotateToInterfaceOrientation:duration: and didRotateFromInterfaceOrientation: methods in the child viewController (unityViewController) are never being called. I have been able to confirm that the parent methods are indeed being called, and in those I make the call to super, but the child methods are never called.

Question:

What is the reason that this default behavior is not occurring? I need both the parent and the child to receive the rotation messages for proper display.

Note: I am aware that I can manually make the calls to these methods in the parent, but I do not want to manually make these calls and add extra code that should be default behavior.

Thank you so much for the help!

like image 756
Sam Avatar asked Mar 28 '14 17:03

Sam


People also ask

What is the difference between root view and child view controllers?

Typically, the system calls this method only on the root view controller of the window or a view controller presented to fill the entire screen; child view controllers use the portion of the window provided for them by their parent view controller and no longer participate directly in decisions about what rotations are supported.

What is the parent of a view controller?

The view controller that is presented by this view controller, or one of its ancestors in the view controller hierarchy. var parent: UIViewController? The parent view controller of the recipient.

Why do I need to associate a child view controller with itself?

Your container view controller must associate a child view controller with itself before adding the child's root view to the view hierarchy. This allows iOS to properly route events to child view controllers and the views those controllers manage.

When is the viewwilllayoutsubviews () method called?

If a view controller is not visible when an orientation change occurs, then the rotation methods are never called. However, the viewWillLayoutSubviews () method is called when the view becomes visible.


1 Answers

In order for your child view controller to receive forwarded orientation callbacks, it must be visible. It's likely that your child view controller isn't visible because its view hasn't been added into the view hierachy.

If you change your method to this, you should start seeing your rotation messages being called:

- (void)addUnityViewController:(UIViewController *)unityViewController 
{
    [self addChildViewController:unityViewController];

    unityViewController.view.frame = self.view.bounds;
    [self.view addSubview:unityViewController.view];
    ... // add some view constraints here

    [self.view sendSubviewToBack:unityViewController.view];       
    [unityViewController didMoveToParentViewController:self];
}

For more information: Responding to Orientation Changes in a Visible View Controller.

like image 123
humblehacker Avatar answered Sep 19 '22 07:09

humblehacker