I have a UIViewController on the More... tab. In viewDidLoad, I set toolbarHidden to NO, and the toolbar appears. However, if I select another tab from More..., then when I return to my original UIViewController, the toolbar is hidden (toolbarHidden is YES). I've checked to be sure it's the same view controller object.
My workaround is to set toolBarHidden to NO in viewWillAppear.
Is this documented behavior that I'm missing or is it a bug?
UPDATE
Here is some fairly trivial sample code. It turns on the toolbar in viewDidLoad and offers a button to toggle the toolbar on and off.
// Test_VC.m
#import "Test_VC.h"
#implementation Test_VC
- (void)viewDidLoad {
[super viewDidLoad];
// for testing to turn the toolbar on and off
UIBarButtonItem *sampleButton = [[UIBarButtonItem alloc]
initWithTitle:#"Toggle TB"
style:UIBarButtonItemStylePlain
target:self action:#selector(toggleToolbar:)];
self.navigationItem.rightBarButtonItem = sampleButton;
// the toolbar should re-appear whenver this view controller is selected
self.navigationController.toolbarHidden = NO;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// if on More..., this line will keep toolbar visible
//[self.navigationController setToolbarHidden:NO animated:NO];
}
- (void)toggleToolbar:(UIBarButtonItem *)sender
{
[self.navigationController setToolbarHidden:!self.navigationController.toolbarHidden animated:YES];
}
#end
To test:
Create a project with numerous tabs, each of which is an instance of this view controller, Test_VC. Have enough tabs so that at least two of these controllers are on the More tab.
Run the app.
Go to the More tab.
Select a "Test_VC" on More (I refer to this as "Test_1"). Notice that the toolbar appears.
Select another Test_VC from More. (I refer to this as "Test_2"). Notice that the toolbar also appears.
Touch "Toggle TB". Notice that the toolbar goes away on Test_2.
Touch More.
Reselect the first Test VC ("Test_1"). Notice that the toolbar is no longer there.
Repeat these tests using Main tab view controllers. Notice that there is no interactions with any others.
In step 4, the toolbar for Test_1 was present. In step 6, the Test_2 toolbar is removed. However, in step 8, the Test_1 toolbar is gone, too, but no change was made to the Test_1 VC.
This demo turns the toolbar on and off via the Toggle TB button. In my app, some of my view controllers simply hide the toolbar in viewDidLoad and some don't. This demo code could be modified to make two view controller versions: some that show the toolbar in viewDidLoad and some that hide the toolbar in viewDidLoad (no need for the Toggle button).
If these view controllers are main tabs (step 9), then each operates independently of the others, as expected.
What I have found: Toolbar visibility on all view controllers launched from More is set by the most recent More view controller that executes viewDidLoad. Thus, viewDidLoad is strange for More tab view controllers.
It's as if there's only one toolbar managed by More. I do not understand this behavior.
Related
Main screen in my app has 2 buttons. When click button 1, show ViewController1. When click button 2, show ViewController2. ViewController1 has 2 bar items. ViewController of each bar item has Back and Done button. Back is back to main menu, Done is used to hide keyboard. I want to control 2 these buttons.
I have 2 directions:
Add Navigation Controller at main screen. It has Back button. Button Done is implemented in ViewController of each bar item. In this case, button Done works not good when change tab bar. I loged and see that, first click in tab bar, it works correct, but click Item1->Item2->Item1, button Done in Item1 this time not correct, because it is still button Done in Item2 Controller.
How to fix in this case?
I hide Navigation Controller in main screen, implement Navigation Controller in Controller of each Tab Bar. In this case, button Done works good, but button Back can't move to main screen when click on it.
How to move to main screen in this case?
Code in AppDelegate.m:
UIViewController *cont = [[VCMainMenu alloc]initWithNibName:#"VCMainMenu" bundle:nil];
self.navController = [[UINavigationController alloc]initWithRootViewController:cont];
[self.window setRootViewController:navController];
Code in MainMenu.m, ViewDidLoad:
self.navigationItem.backBarButtonItem =
[[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStylePlain
target:nil
action:nil];
Code in MainMenu.m, buttonClick:
self.navigationController.navigationBarHidden = YES;
[self.tab setSelectedIndex:0];
[self.navigationController pushViewController:self.tab animated:YES];
Button Done in each class:
UIBarButtonItem *btnDone = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(btnDonePressed:)];
self.navigationController.topViewController.navigationItem.rightBarButtonItem = btnDone;
btnDone.enabled = TRUE;
btnDone.style = UIBarButtonSystemItemDone;
Thanks.
To hide the Keyboard you need to know which textView is firstResponder. You have to implement a dismisskeyboard method for each of your scenes.
Also, why are you coding all the navigation stuff? It would be much easier implementing them via storyboards and segues.
I hide Navigation Controller in main screen, implement Navigation
Controller in Controller of each Tab Bar. In this case, button Done
works good, but button Back can't move to main screen when click on
it. How to move to main screen in this case?
To do that, use
[self.navigationController popViewControllerAnimated:YES];
And as a sidenote #Marcal has a point, I think it might be better if you use storyboards and segues
I am pushing a viewController onto the UINavigationController with animation, and the controller being pushed on is basically doing something like:
--- app delegate:
[((UINavigationController *)window.rootViewController) pushViewController:initialController animated:YES];
--- initial controller:
- (void)viewDidLoad {
[super viewDidLoad];
if (self.shouldSkipThisController) {
SomeOtherViewController *someOther = [[SomeOtherViewController alloc] init];
[self.navigationController pushViewController:someOther animated:NO];
}
}
This is causing some CRAZY behavior which I don't understand at all. Basically, it seems like the navigation items set on SomeOtherViewController are being covered up by some strange other button that has the name of the title in a back button. It looks like although SomeOtherViewController is setting it's own left and right navigation items, they are covered up by the "default" back button--- and then if I tap on that back button, then just the navigation bar at the top animates-- and THEN SomeOtherViewController's navigation items are then there.
The only thing I could find that sort of worked was to either 1) not animate the push of the initial view controller in the app delegate, or 2) move the shouldSkipThisController condition into viewDidAppear: method.
However, neither of those options are ideal... Any help could be greatly appreciated.
In an iOS run on iOS 6.1 (emulated) and 6.1.3 (physical device) application we show an UIActionSheet from a view with the following code:
UIActionSheet *actionCreateNewComment = [[UIActionSheet alloc] initWithTitle:CLocalised(#"EditExistingComment") delegate:self cancelButtonTitle:CLocalised(#"No") destructiveButtonTitle:nil otherButtonTitles: CLocalised(#"Yes"), nil];
[actionCreateNewComment setActionSheetStyle:UIActionSheetStyleBlackOpaque];
[actionCreateNewComment setTag:ActionSheetTagNewComment];
[actionCreateNewComment showFromToolbar:self.navigationController.toolbar];
[actionCreateNewComment release];
The View sets the toolbar with:
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:control];
[self setToolbarItems:[NSArray arrayWithObject:item]];
Where control is an UISegmentedControl.
The code for handling the button actions are:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
bool shouldAddNewComment = buttonIndex == [actionSheet cancelButtonIndex];
[self navigateToCommentScreen:shouldAddNewComment];
}
Every time this action sheet is shown the tool bar will go "blank". Not only for this view but also for the other views.
Here is an example of a work flow:
Note that if I navigate from Instr to Comment without the UIActionSheet, but otherwise the same code, the problem will not appear.
The problem here is that in the "Instr" view the toolbar is empty.
If I pop two more views to return to "List" its toolbar will be empty as well:
Even if I then navigate back to WO and Instr, by allocing and init new forms, and then pushing them, the toolbars will still be empty.
There is another navigation option from the "List" View that shows a "Summary" view. Depending on the data this view will show with or without buttons in the toolbar:
Both "Summary Button" and "Summary empty" are intended views. "Summary hidden" is shown after the UIActionSheet have been shown before navigating between Inst and Comment.
But if I navigate to a "Summary" view that is shown as "Summary Empty" in the picture (intended, due to the data) then the toolbar will start working everywhere again. Or at least until I show the UIActionSheet from the Instr view again.
There are some, in my opinion, strange things about this:
If I navigate to a view where the toolbar is empty, which hides the toolbar, see pic: "SummaryEmpty", then the toolbar will show as intended in the other views.
We use the same code to show an action sheet in other views of the application without any problem
If I run the application on an emulated iOS 5.1 or emulated iOS 5.0 the problem does not appear
Have I missed something when it comes to dismissing the action sheet or how to show it?
Please let me know if you want more information.
Update:
If I forcibly call [self setToolbarItems:nil] after the action sheet button event and then update it with the same items as before the Tool bar will show up as intended.
This does not feel as the right way to do it.
Update 2013-05-28:
Thanks to #LOP_Luke I found out that if I do not navigate to the "Comment" view from -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex but just returned the tool bar will start working again.
So, can there be some kind of problem when I navigate to another view when then clickedButtonAtIndex is still on the call stack?
Update 2013-05-29:
If I add a method:
-(void)commentScreenYes{
[self vanigateToCommentScreen:YES];
}
And change the button code to:
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
bool shouldAddNewComment = buttonIndex == [actionSheet cancelButtonIndex];
if(shouldAddNewComment){
[self performSelectorOnMainThread:#selector(commentScreenYes) withObject:nil waitUntilDone:NO];
return;
}
[self navigateToCommentScreen:shouldAddNewComment];
}
Then it will work for the cancel button, but not for the yes button. The cancel button will also make the toolbar work again after it have been "broken" by the yes button. If I pipe both buttons through this flow (by adding a new method) they will both work.
And still, if I run it at iOs 5.1 it will work no matter which flow I choose.
The – setToolbarItems method is a UIViewController method specific to each child view controller of your navigation controller. Assuming [self navigateToCommentScreen:shouldAddNewComment] pushes a new view controller onto the navigation stack you will have to set the toolbar items for the new view controller too as a separate call, regardless of what the action sheet is doing. For example,
-(void) navigateToCommentScreen:(bool) shouldAddComment{
CommentViewController* viewController = [[CommentViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
[viewController setToolbarItems:self.toolbarItems];
}
Otherwise the new view controller will have no toolbar items and the toolbar will be blank.
Edit
I created a navigation controller with a root view controller that has a toolbar with a UISegmented control. I pushed a new view controller onto the navigation stack via a UIActionSheet delegate method and then popped it back. The toolbar was exactly how it should be on the root view controller (the segmented control faded back in as expected). You must be doing something more complicated with your controller with regards to setting the toolbar items that is causing them to disappear. Without seeing your viewController's source methods it's hard to tell what the problem is. Make sure that you are not setting your toolbar items to nil or resetting them with an empty array somehow.
I am creating an iPhone client for one of my apps that has an API. I am using the GTMOAuth2 library for authentication. The library takes care of opening a web view for me with the correct url. However I have to push the view controller myself. Let me show you some code to make things more clear:
- (void)signInWithCatapult
{
[self signOut];
GTMOAuth2ViewControllerTouch *viewController;
viewController = [[GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:[_account catapultAuthenticaiton]
authorizationURL:[NSURL URLWithString:kCatapultAuthURL]
keychainItemName:kCatapultKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[self.navigationController pushViewController:viewController animated:YES];
}
I have a "plus"/"add" button that I add to the view dynamically and that points to that method:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(signInWithCatapult)];
When I press the "add" button, what is supposed to happen is to open the web view with an animation, and then add an account to the accounts instance variable which populates the table view. This works fine if I add one account, but as soon as I try to add a second account, the screen goes black and two errors appear in the console:
nested pop animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
The only way that I found to avoid this problem was to disable animations when pushing the view controller.
What am I doing wrong please?
Typical situations
You push or pop controllers inside viewWillAppear: or similar methods.
You override viewWillAppear: (or similar methods) but you are not calling [super viewWillAppear:].
You are starting two animations at the same time, e.g. running an animated pop and then immediately running an animated push. The animations then collide. In this case, using [UINavigationController setViewControllers:animated:] must be used.
Have you tried the following for dismissing once you're in?
[self dismissViewControllerAnimated:YES completion:nil];
I got the nested pop animation can result in corrupted navigation bar message when I was trying to pop a view controller before it had appeared. Override viewDidAppear to set a flag in your UIViewController subclass indicating that the view has appeared (remember to call [super viewDidAppear] as well). Test that flag before you pop the controller. If the view hasn't appeared yet, you may want to set another flag indicating that you need to immediately pop the view controller, from within viewDidAppear, as soon as it has appeared. Like so:
#interface MyViewController : UIViewController {
bool didAppear, needToPop;
}
...and in the #implementation...
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
didAppear = YES;
if (needToPop)
[self.navigationController popViewControllerAnimated:YES];
}
- (void)myCrucialBackgroundTask {
// this task was presumably initiated when view was created or loaded....
...
if (myTaskFailed) { // o noes!
if (didAppear)
[self.navigationController popViewControllerAnimated:YES];
else
needToPop = YES;
}
}
The duplicated popViewControllerAnimated call is a bit ugly, but the only way I could get this to work in my currently-tired state.
I have a ViewController which I'm using a modal transition for. It has a toolbar and I've added five items (including space) in interface builder. I'm trying to set the buttons from code, so when the table view in this modal ViewController is being edited, show a 'lock' button, when it's not editing, show an 'unlock' button.
Despite my attempts, the buttons aren't changing.
I've tried (updated 13th Jan):
[self setToolbarItems:...animated:true]; // failed
[self.navigationItem setLeftBarButtonItems:... animated:true]; // also failed, though self.navigationItem is not null
[self.parentViewController setToolbarItems:... animated:true];
[self.navigationController setToolbarItems:... animated:true];
[self.tabBarController setToolbarItems:... animated:true];
[self.navigationItem setLeftBarButtonItems:... animated:true];
[self.navigationController.toolbar setItems:
All of which failed.
This ViewController is shown from another VC (non modal), which is pushed onto a NavigationController.
Am I going about this wrong?
Rather than changing the buttons in the toolbar, I eventually just added a button in Interface Builder and changed the background image:
btnLock.image = [UIImage imageNamed:#"lock_open_white_30.png"];
If you really did need to change the buttons, you'd probably need to create all the buttons and expose them on your ViewController, the use setHidden to hide/show them.