Container View Controller not forwarding appearance methods - objective-c

I'm trying to create a container view controller to hold a UINavigationController and a custom UIViewController together on screen.
I laid it out in a test program and it works perfectly, however when I tried to implement it in my real project the appearance methods for the containing View Controllers never get called.
Working Test:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
MasterStatusViewController *master = [[MasterStatusViewController alloc] init];
[self.window setRootViewController:master];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
InventoryViewController *newInventory = [[InventoryViewController alloc] init];
self.navigation = [[UINavigationController alloc] initWithRootViewController:newInventory];
self.statusRibbon = [[StatusBarViewController alloc] initWithNibName:#"StatusBarViewController" bundle:nil];
[self addChildViewController:self.navigation];
self.navigation.view.frame = self.navigationView.frame;
[self.view addSubview:self.navigation.view];
[self.navigation didMoveToParentViewController:self];
[self addChildViewController:self.statusRibbon];
self.statusRibbon.view.frame = self.ribbonView.frame;
[self.view addSubview:self.statusRibbon.view];
[self.statusRibbon didMoveToParentViewController:self];
}
Failing Project:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
MasterViewController *master = [[MasterViewController alloc] init];
self.centerController = master;
[self.window setRootViewController:master];
[self.window makeKeyAndVisible];
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
LoginViewController *login = [[LoginViewController alloc] init];
self.navigation = [[UINavigationController alloc] initWithRootViewController:login];
self.statusRibbon = [[StatusRibbonViewController alloc] init];
[self addChildViewController:self.navigation];
self.navigation.view.frame = self.navigationView.frame;
[self.view addSubview:self.navigation.view];
[self.navigation didMoveToParentViewController:self];
[self addChildViewController:self.statusRibbon];
self.statusRibbon.view.frame = self.ribbonView.frame;
[self.view addSubview:self.statusRibbon.view];
[self.statusRibbon didMoveToParentViewController:self];
}
The views are arranged correctly and perform as expected, except the appearance methods never get called. I'm quite perplexed. Calling the methods manually doesn't seem to be a solution, as those calls aren't going through either.
EDIT: By appearance method I mean viewWillAppear, viewDidAppear, et al.
SECOND EDIT:
~ snip ~
THIRD EDIT: Upon further inspection, I believe the reason the appearance lifecycle methods aren't being called is because they aren't being called on the container view controller either. I added
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
NSLog(#"MasterViewController VIEW WILL APPEAR");
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSLog(#"MasterViewController VIEW DID APPEAR");
}
to the masterViewController and nothing, for some reason they are never being called.

Solved it. I don't know why the master appearance methods were not being called, a few cleans of xcode seemed to solve that problem.
However, those methods still weren't being forwarded to my other view controllers. Then I came across this link and learned that you always have to forward appearance calls to them no matter what. I was able to fix it by adding:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigation beginAppearanceTransition: YES animated: animated];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.navigation endAppearanceTransition];
}
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigation beginAppearanceTransition: NO animated: animated];
}
-(void) viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.navigation endAppearanceTransition];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

I had a similar issue where I was using the containment features of UIViewController where the appearance methods were not getting forwarded whenever I added a new child view controller to the view.
It turns out that you need to call beginAppearanceTransition:animated: before you add the sub view and endApperanceTransition when you are done. You will need to do this when you add the sub view and also when you remove it in order to trigger the appearance methods.
For your case, I'd try something like this:
self.navigation.view.frame = self.navigationView.frame;
[self addChildViewController:self.navigation];
[self.navigation didMoveToParentViewController:self]
[self.navigation beginAppearanceTransition:YES animated:NO];
[self.view addSubview:self.navigation.view];
[self.navigation endAppearanceTransition];
self.statusRibbon.view.frame = self.ribbonView.frame;
[self addChildViewController:self.statusRibbon];
[self.statusRibbon didMoveToParentViewController:self]
[self.statusRibbon beginAppearanceTransition:YES animated:NO];
[self.view addSubview:self.statusRibbon.view];
[self.statusRibbon endAppearanceTransition];

What do you mean exactly by "appearance methods"? You mean, that the view doesn't appear?
In your working example, you're loading the ribbon view from a nib file:
self.statusRibbon = [[StatusBarViewController alloc] initWithNibName:#"StatusBarViewController" bundle:nil];
while you just init it in the second code example:
self.statusRibbon = [[StatusRibbonViewController alloc] init];
The latter just creates a 'fresh' view, which may result in your perception, that it doesn't appear.

Related

UINavigationController & Auto-Layout: RootViewController's view is not shown

I'm trying to use a navigation controller in my iOS-Project. Here is the setup of my AppDelegate class:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Generate RootViewController (some auto-layout stuff is going on here)
MyLayoutDescriptionGeneratorClass *generator = [MyLayoutDescriptionGeneratorClass new];
MyViewControllerClass *vc = [generator generateViewController];
self.navController = [[UINavigationController alloc] initWithRootViewController:vc];
[self.window setRootViewController:self.navController];
[self.window makeKeyAndVisible];
return YES;
}
The viewDidLoad of my view controller looks like this:
-(void)viewDidLoad{
[super viewDidLoad];
// Generate all subviews and their constraints
self.view = [MyObjectManagerClass viewForParentViewDescription:_parentViewDescription];
self.title = #"Hello";
}
When I Build & Run the navigation bar is shown and its title is set to Hello - unfortunately the view controllers view is not displayed.
If I take out the navigation controller like this
[self.window setRootViewController:self.navController];
everything works great. Can anyone help me please?
I just had to modify my viewDidLoad:
-(void)viewDidLoad{
[super viewDidLoad];
// Generate all subviews and their constraints
UIView *view = [RuiObjectManager viewForParentViewDescription:_parentViewDescription];
self.title = #"Hello";
// Add generated view to self.view and create constraints
[self.view addSubview:view];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[view]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(#"view", view)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[view]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(#"view", view)]];
}

How to change the viewcontroller's background color from gray color to setting's color?

I'm trying to change the viewcontroller's color.
Someone let me know like following.
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
Here is AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[[ViewController alloc] init] autorelease];
} else {
self.viewController = [[[ViewController alloc] init] autorelease];
}
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
This is ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
But, result is that viewcontroller is black screen.
How to change to settings backgroundcolor?
try this
self.view.backgroundColor=[UIColor clearColor];

NavigationBar not displaying properling when pushViewController

The problem is pretty simple to understand with pictures.
I have a UINavigationController that allow the user to switch between to views.
The first view contains a search bar and a table view like so :
The second is a basic view where information about the cell are display
When I click on the search bar, the navigation controller gets hidden and the search bar is now at the top.
Now, if I click on a cell, it goes to the second views, but the navigation bar is first hidden like below :
And then, it automatically appears like that :
I have tried a couple of things like show the navigation bar before pushing the next view controller but it is quite ugly..
Does anyone know how to have the show the navigation bar directly on the second view (like in the contact application)?
[UPDATE] : Code
AppDelegate.m (I'm talking about navigationcontroller2)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
FirstViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
SecondViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
viewController1.managedObjectContext = [self managedObjectContext];
viewController2.managedObjectContext = [self managedObjectContext];
viewController1.viewController2 = viewController2;
UINavigationController *navigationcontroller1 = [[UINavigationController alloc] initWithRootViewController:viewController1];
[navigationcontroller1.navigationBar setTintColor:[UIColor lightGrayColor]];
UINavigationController *navigationcontroller2 = [[UINavigationController alloc] initWithRootViewController:viewController2];
[navigationcontroller2.navigationBar setTintColor:[UIColor lightGrayColor]];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:navigationcontroller1, navigationcontroller2, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
FirstView.m
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar {
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!noResultsToDisplay) {
PinDetailsViewController *pinDetailsViewController = [[PinDetailsViewController alloc] initWithNibName:#"PinDetailsViewController" bundle:nil];
NSManagedObject *managedObject = [fetchedResultsController objectAtIndexPath:indexPath];
Pin *pin = (Pin *) managedObject;
[self.navigationItem setTitle:#"Pins"];
[self.navigationController pushViewController:pinDetailsViewController animated:YES];
[pinDetailsViewController updateWithPin:pin];
}
}
If you need anything else, just ask but I think it's all there.
Try to use this code in each viewcontroller.
- (void) viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
Before you push the new view controller, you should unhide the navigation bar:
[self.navigationController setNavigationBarHidden:NO animated:YES];
I had a similar problem with the position of my navbar. Mine was moving up behind the status bar, and I fixed the issue by manually setting the navbar frame:
-(void)adjustNavBarOrigin
{
CGRect r = self.navigationController.navigationBar.frame;
r.origin = CGPointMake(0, 20); // 20 is the height of the status bar
self.navigationController.navigationBar.frame = r;
}
I had to call this method in a number of places, including viewWillAppear: and didRotateFromInterfaceOrientation:, but it worked a treat :)
Hiding the UINavigationBar can disturb the properties sometimes. Try using the property alpha instead of hidden.

White screen after presenting a modal view controller

I'm getting a white screen after presenting a modal view controller. This is how I do it:
SomeViewController *controller = [[[SomeViewController alloc] initWithManagedObjectContext:managedObjectContext] autorelease];
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:controller] autorelease];
[navController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentModalViewController:navController animated:YES];
The navigation bar works fine, as I set it up in SomeViewController, but the view's contents are not visible, and all I see is the white background color of the root window.
The strange thing is, that this used to work, but now it doesn't for some reason.
What could be the problem?
EDIT:
This is how I create SomeViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
[self setTitle:#"Some View"];
UIBarButtonItem *sortButton = [[[UIBarButtonItem alloc] initWithTitle:#"Sort" style:UIBarButtonItemStylePlain target:self action:#selector(sortButtonClicked:)] autorelease];
[[self navigationItem] setRightBarButtonItems:[NSArray arrayWithObjects:sortButton, [self editButtonItem], nil] animated:YES];
UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(dismissModalViewControllerAnimated:)] autorelease];
[[self navigationItem] setLeftBarButtonItem:backButton];
// Hack to force landscape orientation
UIViewController *controller = [[UIViewController alloc] init];
[self presentModalViewController:controller animated:NO];
[self dismissModalViewControllerAnimated:NO];
[controller release];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
The white screen was caused by the xib file of the controller not being part of the target(its target membership checkbox was unchecked).
Do you happen to have some other init meted also in the SomeViewController class? Please post the whole .m file. If so, you can try to delete the initWithNibName method and check if it shows the content.
EDIT:
Another strange point is the initWithManagedObjectContext method you are using on the viewController instance. Can you explain it?
try
SomeViewController *controller = [[[SomeViewController alloc] init] autorelease];
it should work fine.

viewWillAppear is not called

I know that viewWillAppear is not called on pop/push views, but I really need that method. Here is what I try
I added UINavigationControllerDelegate and adopt
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
[viewController viewWillAppear:animated];
}
-(void)viewWillAppear
{
NSLog(#"Log");
}
but viewWillAppear is still not invoked
EDIT
AppDelegate.m
self.navigationController = [[UINavigationController alloc]init];
[self.window setRootViewController:self.navigationController];
FirstView *fview = [FirstView]alloc]init];
[self.viewController pushViewController:fview animated:YES];
FirstView.m
....
-(void)viewWillAppear
{
NSLog(#"Logged");
}
....
The clue is here:
[viewController viewWillAppear:animated];
}
-(void)viewWillAppear
You call a method that takes one parameter. But your method doesn't have one. In Objective C terms that's a completely different method.
It should look like this:
-(void)viewWillAppear:(BOOL)animated {
// blah
}
do you have navigation controller on window?
paste your appdelegate.m
my working code:
self.navController = [[[CustomNavigationController alloc] initWithRootViewController:[[[HomeViewController alloc] init] autorelease]] autorelease];
[self.window addSubview:navController.view];
[self.window makeKeyAndVisible];