popToRootViewControllerAnimated toolbar not correctly updating - uinavigationcontroller

I have a UITabBarController whose tabs are UINavigationController. I have initialized each navigationController by:
iPhoneApp *appDelegate = (iPhoneApp *)[[UIApplication sharedApplication] delegate];
[appDelegate.navigationController2 initWithRootViewController:countryController];
I then drill down the navigationController with:
[self.navigationController pushViewController:myViewController animated:YES];
I want to pop to the root of my navigationController(s) when the user clicks on a tabBar tab.
[delegate.navigationController2 popToRootViewControllerAnimated:NO];
This seems to work great when I only pushViewController one level, but fails when I drill down multiple levels in my navigationController. What happens is that it pops to root but doesn't contain my Root's backbutton or title:
self.navigationItem.title = #"My title";
self.navigationItem.hidesBackButton = YES;
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStyleDone
target:self
action:#selector(handleBack:)];
if I don't poptoroot and just use the navigationControlls back button, everything works correctly.
I logged my viewControllers before and after i poptoroot
before:
MainCountryController: 0x3d53650,
IndividualCountryMfgViewController: 0x3d67d50,
IndividualCountryProductViewController: 0x3d60870
after:
MainCountryController: 0x3d53650
it's the right view, but wrong toolbar title and backbutton.
Anyone have any ideas? Thanks for your help.

I got this working by disconnecting my navigation controllers from IB an just creating them programatically.

Related

Odd UINavigationController and UIPopOverController behavior

I am presenting a popover with my viewcontroller:
UIBarButtonItem *barButton = (UIBarButtonItem*)sender;
SettingsViewController *settingsViewController = [[SettingsViewController alloc] initWithNibName:nil bundle:nil];
[self presentPopoverFromBarButtonItem:barButton andController:settingsViewController andSize:CGSizeMake(RECT_POPOVER_SETTINGS.size.width, RECT_POPOVER_SETTINGS.size.height)];
and inside this view controller I have a button that pushes another view controller.
AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:anotherViewController animated:YES];
Now in this view controller I have an action, and when it's done I do:
[self.navigationController popViewControllerAnimated:YES];
Now the strange behavior is that when I pop the view controller, the
viewWillAppear
method gets called in SettingsViewController, then the breakpoints come back to pop method inside my anotherViewController.
This is a universal App so I am using this same setup on the iPhone, but without the initial UIPopOverController. This is functioning properly in the iPhone (with no popovers, pop method gets called first, then viewWillAppear), but on the iPad the viewWillAppear gets called first, then pop.
So my question is, can somebody explain why this is happening?
Thanks.

Custom Image in navigationbar hiding the custom navigationbar buttons

First of all I explain what i am doing. I created a navigation based application. I have to add a custom image in the navigationbar. I added the image by using -
[self.navigationController.navigationBar insertSubview:image atIndex:0];
After this i added two custom buttons left and right to the navigation bar of the same view.I have another view and on this view i also added two custom buttons left and right to the navigation bar. All is fine till now but as i navigate to my second view my custom buttons that i am adding to the navigation controller on viewwillappear doesn't show. I used this code to add custom buttons to navigation bar -
UIBarButtonItem *customHome = [[UIBarButtonItem alloc] initWithCustomView: buttonHome];
[self.navigationController.navigationItem setLeftBarButtonItem:customHome];
Please suggest what's wrong in this. :(
You're trying to set the navigationItem on the navigation controller instead of the view controller.
If you have embedded your UIViewController in a UINavigationController then in viewDidLoad of the View Controller you could, for example, make the title a UISearchBar (that you dragged to the UIViewController in Xcode IB) and put 2 buttons on the right like this:
UIBarButtonItem *componentsButton = [[UIBarButtonItem alloc] initWithTitle:#"components" style:UIBarButtonItemStylePlain target:self action:#selector(componentsButtonTapped:)];
UIBarButtonItem *settingsButton = [[UIBarButtonItem alloc] initWithTitle:#"settings" style:UIBarButtonItemStylePlain target:self action:#selector(settingsButtonTapped:)];
self.navigationItem.rightBarButtonItems = [NSArray arrayWithObjects:componentsButton, settingsButton, nil];
self.navigationItem.titleView = searchBar;
The issue here is the distinction between UINavigationController, which manages UINavigationBar, and UINavigationItem, which you and UINavigationController co-manage. (Don't forget the UINavigationBarDelegate protocol, which has little used but useful methods.)

Refreshing tabbarcontroller views on logout in iPhone application

We have a tab bar + navigation control project. We have created a tab bar through interface builder and added all tab items to the tab bar controller through through interface builder.
Our application has a login screen which we are showing as a modal form at the beginning. Once the user is authenticated, the login screen is dismissed (using dismissModalScreen) and the MainWindow is shown. This is all working fine.
Now, we have a logout option clicking on which we should show the login screen back. We are able to show that as well. But the issue is once the user is authenticated again, we want all the screens to be loaded freshly. Currently, all screens maintain their state and retain previous data.
What we have tried to do is:
[AppDelegate tabBarController release];
AppDelegate.tabBarController = nil;
We have tried releasing the tabBarController and setting it to nil. But once the view is shown, we are not able to select any of the tabs and the view is blank.
What we need is:
Once the user logs in second time, how to release and reload each viewcontroller which are part of tabbar.
Your help will be greatly appreciated.
We have found a way out. What we are doing now is, once the user logs back in, we are releasing the view controllers and recreating them and setting it back to the uitabbar.
NSMutableArray *arrControllers = [[AppDelegate.tabBarController.viewControllers] mutablecopy];
[arrControllers removeAtIndex:3];
[arrControllers removeAtIndex:2];
----Create New Controllers
UIViewController viewController2 = [[UIViewController alloc] initWithNibName:#"viewController2" bundle:nil] autorelease];
UIViewController viewController3 = [[UIViewController alloc] initWithNibName:#"viewController3" bundle:nil] autorelease];
--Create Nav controller
UINavigationController navViewController2 = [[[UINavigationController alloc] initWithRootViewController:viewController2 ] autorelease];
UINavigationController navViewController3 = [[[UINavigationController alloc] initWithRootViewController:viewController3 ] autorelease];
[arrControllers addObject:navViewController2];
[arrControllers addObject:navViewController3];
[AppDelegate.tabViewController setViewControllers:arrControllers];
It is working fine after this change.
Only problem we faced was if we release all objects from the array, we get a carsh. Is it because, when you release allObjects, the first controller which is the RootViewController is getting released?
Thanks

UINavigationController popToRootViewController doesn't reset Title, clear backbutton

I am stuck trying to customize UINavigationController's backbutton.
In RootViewController I set self.title in viewDidLoad, and this string appears in Navigation Bar. In -didSelectRowAtIndexPath I create child view controller, configure back button and call -pushViewController. Processing for child will push child viewcontrollers onto the stack; I need back button to pop to initial view, just as when going back from first child view controller. Currenty backbutton will pop to prior view, so if there are 5 child view controllers on the stack, I have to hit back button 5 times to get to root view.
I am unable to get action to fire off when back button is displayed. I am able to popToRootViewController when in child VC; however, backbutton now appears on root view(!) and I have to hit backbutton once more to restore original title and remove backbutton.
Here is part of root -viewDidLoad:
- (void)viewDidLoad {
self.title = #"My Nav Bar Title"; // displays on root navigation bar title
// some setup code...
[super viewDidLoad];
}
Here is part of -didSelectRowAtIndexPath, where selecting a tableview cell results in child view being pushed onto stack:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ChildVC *child = [[ChildVC alloc]
initWithNibName:#"Child"
bundle:nil];
[self.navigationController dismissModalViewControllerAnimated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Quiz" style:UIBarButtonItemStylePlain target:self action:#selector(backToMenu)];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[self.navigationController pushViewController:child
animated:YES];
[child release];
}
Here is action method which doesn't fire when backbutton is pressed:
-(void)backToMenu {
NSLog(#" in root backToMenu");
[self.navigationController popViewControllerAnimated:YES];
}
ChildVC will also create a new child in its -didSelectRowAtIndexPath and push the new child controller, as the next child 'page':
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
Child *newChild = [[Child alloc]
initWithNibName:#"Child"
bundle:nil];
[self.navigationController dismissModalViewControllerAnimated:YES];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
self.title = self.quizString; // child view correctly displays customized title
UIBarButtonItem *backButton = [[UIBarButtonItem alloc]
initWithTitle:#"Quiz"
style:UIBarButtonItemStylePlain
target:self
action:#selector(backToMenu)];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[self.navigationController pushViewController:newQuestion
animated:YES];
[newChild release];
}
In Child -viewWillDisappear I set a global variable so I known when to push new child and when to pop back to root:
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:YES];
if (startOver) {
[self backToMenu];
}
}
Child -backToMenu:
-(void)backToMenu {
[self.navigationController popToRootViewControllerAnimated:YES];
}
Here is the sequence when back button is pressed in Child:
-- Child -viewWillDisappear is invoked, calls -backToMenu
-- -backToMenu calls popToRootViewControllerAnimated:
-- Child -viewWillDisappear is invoked again, calls -backToMenu
-- root -viewWillAppear is invoked
-- control returns to Child -backToMenu
Root view appears correctly, but Nav bar contains back button and title just like it still was a Child view. Pressing back button removes back button an restores original title.
How can I make this work? Ideally I would like to only have 1 child view on the stack, but I can't figure out how; then the back button would go back to root view. But when I tried this, I got NSInvalidArgumentException', reason: 'Pushing the same view controller instance more than once is not supported...'
Also, anything obvious why action is not fired when backbutton is pressed? Any help is GREATLY appreciated...thx
UIBarButtonItem *btnBack=[[UIBarButtonItem alloc]initWithTitle:#"" style:UIBarButtonItemStyleDone target:self action:#selector(back:)] ;
self.navigationItem.leftBarButtonItem=btnBack;
//Add image on back button
UIImage *backButtonImage = [[UIImage imageNamed:#"btn_back.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 6)];
[btnBack setBackgroundImage:backButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
put this code in your view controller[initWithNibName method]form where you want to pop at root view controller
- (void) back : (id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}
uhm, your backButton calls popToRootViewController, which calls viewWillDissapear, which, if startOver is true calls popToRootViewController AGAIN?
what happens if it's false anyway? it continues the popToRootViewController called earlier ...
backButton->popToRoot->viewWillDissapear->check startOver
->YES->popToRoot->viewWillDissapear again->check startOver again->??
->NO->continue the disappearing of the view that was called also by popToRoot
isn't that if there redundant, since both it's branches continue previously popToRoot or call popToRoot again?
why not test for startOver first(in your backToMenu), then popToRootViewController if true?

uinavigationController's toolbar with custom items

I am trying to use the NavigationController's toolbar in my app. This toolbar's toolbarItems are suppose to change depending on which view controller is presented. this is very basic.
What I am trying to do is to add custom buttons to the toolbar using the UIBarButtonItem's "initWithCustomView:" method. However, the button won't show up on the toolbar. But if I create the UIBarButtonItem using the "initWithTitle:" or "initWithBarButtonSystemItem:" method, the button show up. For example, look at the code below:
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks target:self action:nil];
UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:#"edit" style:UIBarButtonItemStylePlain target:self action:nil];
NSArray *array = [[NSArray alloc] initWithObjects:item1, item2, nil];
[self setToolbarItems:array];
If this is done, buttons show up on the toolbar. But, if I were to do the following:
UIButton* replyBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[replyBtn setImage:[UIImage imageNamed:#"Reply_Message.png"] forState:UIControlStateNormal];
[replyBtn addTarget:self action:#selector(replyButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
replyBtn.frame = CGRectMake(10, 0, 40, 40);
UIBarButtonItem *replyButton = [[UIBarButtonItem alloc] initWithCustomView:replyBtn];
UIBarButtonItem *item1 = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemBookmarks target:self action:nil];
UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:#"edit" style:UIBarButtonItemStylePlain target:self action:nil];
NSArray *array = [[NSArray alloc] initWithObjects:item1, replyButton, item2, nil];
[self setToolbarItems:array];
In this code, only the item1 and item2 are displayed on the toolbar. replyButton is not shown on the toolbar. There is blank space at the place where the button is suppose to be at.
If this same code used on a regular toolbar that I create instead of NavigationController's toolbar, the button shows up. I am trying to just use one toolbar throughout the app to have the same feel that Apple's Mail application does. The reason that I need to use the "initWithCustomView:" method is because one of the icons is colored and this is the only way it shows up colored on a normal toolbar. Now, I have looked through apple documentation and there isn't any mention of why the "initWithCustomView:" method couldn't be called (or maybe I couldn't find it).
Could please somebody shine some light on this topic to help me point in the right direction. thanks in advance guys.
I can't see the difference from what you tried, but it eventually worked for me, with that code:
//////////////////////////////////////////////////////////////////////////////////////////////
/////>>>> Adding buttons for browsing in the toolbar of the popover's navigation controller///
//////////////////////////////////////////////////////////////////////////////////////////////
//>>>>Create a goBack button
goBack = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *goBackImage = [UIImage imageNamed:#"back1.png"];
[goBack setImage:goBackImage forState:UIControlStateNormal];
[goBack addTarget:self action:#selector(goBackClicked:) forControlEvents:UIControlEventTouchUpInside];
goBack.frame = CGRectMake(0,0,goBackImage.size.width,goBackImage.size.height);
//Create a Bar button to hold this button
UIBarButtonItem *goBackBarButton = [[[UIBarButtonItem alloc] initWithCustomView:goBack] autorelease];
UIBarButtonItem *flex1 = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease];
UIBarButtonItem *addButton = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRewind target:nil action:nil] autorelease];
NSArray *arrayOfButtons = [[[NSArray alloc] initWithObjects:goBackBarButton, flex1, addButton, nil] autorelease];
[self setToolbarItems:arrayOfButtons];
Note few differences from yours (maybe that's where the catch? I'm not sure):
1. my buttons are not allocated locally in the method, but in the class (you know, the property, synthesize, etc)
2. yours
[replyBtn setImage:[UIImage imageNamed:#"Reply_Message.png"] forState:UIControlStateNormal];
where mine looks a bit different
[goBack setImage:goBackImage forState:UIControlStateNormal];
Try these tiny changes, maybe it will work :)
I was having the same problem. It turns out that the toolbar for the UINavigationController resets it's items every time a new view gets pushed on the stack. I was trying to set the toolbar items in the applicationDidFinish function, and it was not working. It worked once I set the toolbar itms in the - (void) viewDidAppear function of the viewController that was being pushed onto the navigation stack.
So, it seems like if you want the navigation controller to keep the same toolbar items throughout the application, you have to set the toolbar items in each view that you push onto the navigation controller after the view appears.
I hope that helps!
I'd wager a guess that the item isn't showing up because its view doesn't have anything in it. Are you sure there's an image called Reply_Message.png in your project? [UIImage imageNamed:#"Reply_Message.png"] might be nil.
You can use one toolbar throughout your app without using the navigation controllers toolbar. Since your code works with a non-navigationController toolbar, this might be the easiest way to accomplish what you want. In your app delegate, try adding a toolbar to window, like this. This way it is persistent throughout the app. Make sure you consider a scheme that will let you access the toolbar to add/remove buttons, or hide/show it from different view controllers.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
/////// frame sizes ////////
// compensate for the status bar
int statusBarHeight = 20;
// toolbar
int toolbarWidth = window.frame.size.width;
int toolbarHeight = 30; // I think standard size is 30
int toolbarxOffset = 0;
int toolbaryOffset = window.frame.size.height - tHeight;
CGRect toolbarFrame = CGRectMake(toolbarxOffset,
toolbaryOffset,
toolbarWidth,
toolbarHeight);
/////// toolbar //////////////////////
self.myPersistentToolbar = [[UIToolbar alloc] initWithFrame:toolbarFrame];
[window addSubview:self.myPersistentToolbar];
}

Resources