Popping UIViewController causes previous view of UIViewControllers to change position

I have a UINavigationController with a UIViewController set as its rootController, it contains a background on the UIView using a set of images located below the navBar. Then I click on the new UIViewController navigation controller and when I click the back button, the previous controller looks different. Using the visual debugger, I can see that self.view has moved completely below the navBar where it was at the top previously. I have no idea, and I am puzzled over why this might happen. Before Navigation stack Push

enter image description here

-(void)pushIPhoneMessagingContactsController:(MessageContactsViewController *)contactsController{
    self.selectorView.hidden = YES;
    [self.navigationController pushViewController:contactsController animated:YES];
}

      

In RootViewController (iPhoneMessagingNotificationsController)

-(void)viewWillAppear:(BOOL)animated{
    self.selectorView.hidden = NO;
    [[[self navigationItem] leftBarButtonItem] setTintColor:[UIColor blackColor]];
    [[UIApplication sharedApplication]      setStatusBarStyle:UIStatusBarStyleDefault];

    if ([_displayType intValue] == MESSAGES_SHOWING) {
        [self.notificationsViewController.view removeFromSuperview];
        [self.contentView addSubview:_messagesViewController.view];
    } else {
        [self.messagesViewController.view removeFromSuperview];
        [self.contentView addSubview:_notificationsViewController.view];
    }

}

      

+3


source to share


2 answers


It seems that the offending line was in the viewWillAppear method of the pressed UIViewController

self.navigationController.navigationBar.translucent = YES;

Elsewhere, this navigationBar is set to be semi-transparent:

 [self.navigationController.navigationBar setBackgroundImage:[UIImage new]
                                              forBarMetrics:UIBarMetricsDefault];
 self.navigationController.navigationBar.shadowImage = [UIImage new];
 self.navigationController.navigationBar.translucent = YES;

      



and make it solid again:

 self.navigationController.navigationBar.shadowImage = nil;
 self.navigationController.navigationBar.translucent = NO;

      

but this code seems to be messing with the layout, so maybe there is another way to change the opacity of the navBar and statusBar without affecting the layout?

+2


source


What you are currently trying to do is hide or show selectorView

, which should really only be shown for one specific view controller.

Here's an encapsulated way to solve this problem, making you selectorView

part of the root view controller by removing the connection to other view controllers. They no longer need to know about it or hide it.

Add your selector to your rootViewController

titleView navbar. (You can do this in code, or drop it in the Storyboard and add an IBOutlet for it.)

self.navigationItem.titleView = selectorView;

      

Now, when you click another view controller, its title will replace the rootViewController's view title selectorView

. Your other view controllers don't need to know anything about this view.

This is a good approach to overall design. Anytime you have a control that should only appear on one controller navigation bar, you want to make it part of that view controller navigationItem

(titleView, or left or right pane items). IOS will show the control when it is a view manager and hide the control when that view controller is no longer the top-level controller on the navigation controller stack.

As far as the 64-pixel height issue is concerned, it is probably due to some complexity in the rootViewController hierarchy that shouldn't be there.

In iOS 7/8, the content of the view is displayed by default under the transparent navigation bar. Apple has handled this freely for you by inserting the first kind of view hierarchy.



From your code, it appears that you are trying to "hide" or "show" (un) the selected view of the viewController.

Each view controller must have a view that it controls. The view controller should not try to manipulate other views of the view , or add other views of the view to its own view hierarchy.

Here Apple has recommended an approach to this. Use containerView

in root controller root. The whole purpose of a container view is to encapsulate a view controller in a view. Since yours selectorView

changes the view that is displayed, you have a transition to view the container from one view controller to another. (If you don't know how to do this, check out this answer .)

Connect containerViewView to rootViewController so Auto Layout can size it.

Now your view hierarchy looks like view -> containerView, not view -> hidden view of unselected view controller, shown view of selected controller. Apple can adjust the first insert of the view so nothing is misaligned (by the height of the nav control).

Update:

This question talks about scrollViewInsets

and how they can be set on a view-controller-by-view-controller. If you have a view controller and do not want its content to appear below the panel, clear this check box.

But the best way to deal with this is to "standardize" your user interface, so it doesn't differ from the viewport. Either make the bar always translucent or not always translucent. This makes the transition less "annoying" for users.

+1


source







All Articles