Tutorial :NavigationItem setTitle doesn't work for second level UIViewController



Question:

in my app i have an UITabBarController with UINavigationControllers initialized like this

UINavigationController *newsNavigationController = [[UINavigationController alloc] initWithRootViewController: newsViewControler];  

newsViewController is an UIViewController. When i press the button in the tabbar to show the navigation item with the newsViewController the title in the navigation bar is set ok. in the newsViewController i have a method setup that i call after init. In the setup method i set the title like this [[self navigationItem] setTitle:[category_c title]];

The problem comes now, in my newsViewController i have a tableView, when i touch a cell i want to push a UIViewController with the selected news and in the navigation bar to show the title.

In the UIViewController i have the same setup method in which i setup the title like above. The problem is that is not shown. The navigation item is not null because i can call self.navigationItem.hidesBackButton = YES; and it hides the backbutton every time but the title isn't shown.

I create and push the news UIViewController like this when a cell is touched

if(newsViewController == nil){          newsViewController = [[NewsViewController alloc] init];          [newsViewController setup];      }      [self.navigationController pushViewController: newsViewController animated:YES];  

The setup method in the newsViewController looks like this:

- (void) setup {      self.navigationItem.hidesBackButton = YES;      [self.navigationItem setTitle:@"my view"];  }  

in the newsViewController i have viewDidLoad and tried to set the title there but with no success.

  • (void)viewDidLoad { self.navigationItem.title = @"Test"; [super viewDidLoad]; }

if after [self.navigationController pushViewController: newsViewController animated:YES]; i write [[self.navigationController.viewControllers objectAtIndex:0] setTitle:@"myTitle"]; the UIViewController that contains the UITableView gets the title myTitle instead of the newsViewController that i pushed when i touched the cell.

any pointers? i can't understand why the title is not set correctly.

EDIT2: After reading a little more and going through my code with the debugger step by step and comparing the rootviewcontrollers with the childViewControllers i've observed that in the viewDidLoad method of the childViewController after setting self.title = @"title" the navigationItem is created so it's not the nil situation. In the debugger when i expand the _navigationItem variable the field _navigationBar is nil after leaving viewDidLoad, in the rootViewControllers the navigationBar is NOT NULL and the title is there. I read that if the navigationBar is null the title will not show up. In the image is what i've seen in the debuger. alt text http://img138.imageshack.us/img138/1513/picture2bq.png now i'm searching in this direction.

EDIT1: below is the code for the parentViewController, firstChildViewController and second ChildViewController. the parentViewController is viewed(the title is OK). I press a button on the navigationBar that calls bearbeitenAction -> the first child is pushed(title is not showed). On the navigation bar of the firstChildViewController i have a button that when is pressed pushes a new ViewController on the stack(secondChildViewController). The title of the second ChildViewController is not ok. When i press Back the title of the firstChildViewController is showed Ok.

parentViewController:

    //MARK: -      //MARK: Initialization methods      - (void) setup {          dataManipulator = [[DataManipulation alloc] init];          dataManipulator.delegate = self;            [self.tabBarItem initWithTitle:[NSString stringWithFormat:@"%@",[category_c title]] image:[UIImage newImageFromResource:[category_c icon]] tag:0];            searchResults = nil;          companyDetailsPushed = NO;      }        //MARK: -      //MARK: ViewControllerMethods      // Implement loadView to create a view hierarchy programmatically, without using a nib.      - (void) loadView {          NSLog(@"WatchlistViewController: loadView");            UIView *mainView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] applicationFrame].size.width, [[UIScreen mainScreen] applicationFrame].size.height)] autorelease];          [mainView setBackgroundColor:[UIColor whiteColor]];          mainView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;          mainView.contentMode = UIViewContentModeScaleToFill;          [mainView setAutoresizesSubviews:YES];                companiesTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 44, [[UIScreen mainScreen] applicationFrame].size.width, 322)];          companiesTable.delegate = self;          companiesTable.dataSource = self;          [mainView addSubview:companiesTable];          [companiesTable release];                self.view = mainView;      }        - (void)viewDidLoad {          [super viewDidLoad];          if(![[category_c subtitle] isEqualToString:@""]) {              self.title = [category_c subtitle];          }          else {              self.title = [category_c title];          }      }        - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {            if(companyDetailsViewController == nil) {              companyDetailsViewController = [[CompanyDetailsScrollViewController alloc] init];              [companyDetailsViewController setup];          }            [watchlistDoneBtn setHidden:TRUE];          companyDetailsPushed = YES;            if(viewMode == SearchViewMode)              [companyDetailsViewController setCompany:[searchResults objectAtIndex:indexPath.row]];          else if(viewMode == WatchlistViewMode)              [companyDetailsViewController setCompany:[[[Financial_deAppDelegate sharedAppDelegate] watchlistCompanies] objectAtIndex:indexPath.row]];            [[self navigationController] pushViewController:companyDetailsViewController animated:YES];      }    - (void) bearbeitenAction:(UIButton *) sender {      NSLog(@"Berbeiten btn was pressed");      if(berbeitenViewController == nil){          berbeitenViewController = [[BerbeitenViewController alloc] init];          [berbeitenViewController setup];      }      [self.navigationController pushViewController:berbeitenViewController animated:YES];  }  

firstChildViewController = berbeitenViewController in the code:

- (void) setup {      self.navigationItem.hidesBackButton = YES;  }    // Implement loadView to create a view hierarchy programmatically, without using a nib.  - (void)loadView {      NSLog(@"BerbeitenViewController: loadView");        UIView *mainView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] applicationFrame].size.width, [[UIScreen mainScreen] applicationFrame].size.height)] autorelease];      [mainView setBackgroundColor:[UIColor darkGrayColor]];      mainView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;      mainView.contentMode = UIViewContentModeScaleToFill;      [mainView setAutoresizesSubviews:YES];        berbeitenBackBtn = [[UIButton alloc] initWithFrame:CGRectMake(5, 23, 69, 36)];      [berbeitenBackBtn setBackgroundImage:[UIImage newImageFromResource:@"back_btn.png"] forState:UIControlStateNormal];      [berbeitenBackBtn addTarget:self action:@selector(popViewController:) forControlEvents:UIControlEventTouchUpInside];      [berbeitenBackBtn setEnabled:TRUE];      [self.navigationController.view addSubview:berbeitenBackBtn];      [berbeitenBackBtn release];        berbeitenAddBtn = [[UIButton alloc] initWithFrame:CGRectMake(260, 23, 55, 36)];      [berbeitenAddBtn setBackgroundImage:[UIImage newImageFromResource:@"bearbeiten_add_btn.png"] forState:UIControlStateNormal];      [berbeitenAddBtn addTarget:self action:@selector(addCompany:) forControlEvents:UIControlEventTouchUpInside];      [berbeitenAddBtn setEnabled:TRUE];      [self.navigationController.view addSubview:berbeitenAddBtn];      [berbeitenAddBtn release];        companiesTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] applicationFrame].size.width, 366)];      companiesTable.delegate = self;      companiesTable.dataSource = self;      [mainView addSubview:companiesTable];      [companiesTable release];        self.view = mainView;  }    - (void)viewDidLoad {      NSLog(@"BerbeitenViewController viewDidLoad");      [super viewDidLoad];      self.title = @"Edit watchlist";  }    //MARK: Buttons actions    - (void) popViewController:(UIButton *) sender {      NSLog(@"Pop BerbeitenViewController");      [self.navigationController popViewControllerAnimated:YES];  }    - (void) addCompany:(UIButton *) sender {      NSLog(@"Berbeiten addCompany btn pushed");      if(searchViewController == nil){          searchViewController = [[SearchViewController alloc] init];          [searchViewController setup];      }      [self.navigationController pushViewController:searchViewController animated:YES];  }  

secondChildViewController = searchViewController in code

- (void) setup {      self.navigationItem.hidesBackButton = YES;  }    // Implement loadView to create a view hierarchy programmatically, without using a nib.  - (void)loadView {      NSLog(@"BerbeitenViewController: loadView");        UIView *mainView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen] applicationFrame].size.width, [[UIScreen mainScreen] applicationFrame].size.height)] autorelease];      [mainView setBackgroundColor:[UIColor darkGrayColor]];      mainView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;      mainView.contentMode = UIViewContentModeScaleToFill;      [mainView setAutoresizesSubviews:YES];        searchViewBackBtn = [[UIButton alloc] initWithFrame:CGRectMake(5, 23, 69, 36)];      [searchViewBackBtn setBackgroundImage:[UIImage newImageFromResource:@"back_btn.png"] forState:UIControlStateNormal];      [searchViewBackBtn addTarget:self action:@selector(popViewController:) forControlEvents:UIControlEventTouchUpInside];      [searchViewBackBtn setEnabled:TRUE];      [self.navigationController.view addSubview:searchViewBackBtn];      [searchViewBackBtn release];        self.view = mainView;  }      // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.  - (void)viewDidLoad {      [super viewDidLoad];      self.title = @"Edit Watchlist";  }  


Solution:1

EDIT #2

I looked through your code and everything seems okay. The only thing that looks out of place to me is that you are adding a subview to the navigation controller instead of using the child controller's navigationItem. I have never seen it done this way. Each ViewController has a UINavigationItem property that represents the view controller when it is pushed onto a navigation bar. Just read through the Overview of the documentation for some background.

That NavigationItem has a title, left-button and right-button that you can set... I would try setting your buttons to those properties because by adding subviews to the navigation controller it could be doing something funky with the title... Again, I have never seen it done the way you are doing it so I 'm not really sure if it is right or wrong. The only changes you will have to make is changing the buttons to the UIBarButtonItem class. Give it a try.

Original

The root view controller is at index 0 in the array... so if you doing this:

[[self.navigationController.viewControllers objectAtIndex:0] setTitle:@"myTitle"]  

it will always set the root's title. Try to do it at:

objectAtIndex:([self.navigationController.viewControllers count] - 1)  

It might even be easier to do this sort of setup in the child controller's viewWillAppear method... that way you don't have to search through the navigation controller's children for the correct view controller.

hope this helps

EDIT You could try ONLY setting the title in the init method:

-(id)init {      if (self = [super init]) {          self.title = @"My Title";      }      return self;  }  

This way, you are allowing the object's init method to be in charge of initializing the object's values (which is a good thing).


Solution:2

You should move the setup code to the viewDidLoad method instead. The viewDidLoad is called when the navigation item has already been setup for you.

To set the title, simply use self.title = @"my view"; - you should not set the title directly on the navigationItem.


Solution:3

the source of the problem was the custom background image for the navigationBar that i added using the method found at this address http://sebastiancelis.com/ . Basically what happened was and i quote from the author:

By using a category, we could easily add our own setBackgroundImage: method and call it whenever we create a UINavigationBar or UINavigationController. This method would just add a UIImageView as a subview to the navigation bar and then send that subview to the back of its superview.

However, if you try this you will quickly see that it only kind of works. The UIImageView is definitely visible and even initially at the correct z-index. However, once you push or pop a view controller onto the navigation controller's stack, you will see that the background image is no longer in the background. Instead, it blocks out the title and navigation bar buttons. This is definitely not what we want.

when i found this solution for changing the background of the navigationBar i was pretty sure that i got it right but it seems i didn't..

thank you again for your time!


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »