Assuming we are having three screens that are pushed after one another like this
A->B->C
And screen A is originally in a tabBar.
The navigation bar should be hidden in screen C and visible in all of the rest.To do this am doing the following
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden: YES animated:NO];
}
The viewWillAppear gets called in all of the cases but hiding or showing the navigationBar is not necessarily gets reflected on the UI.
For example if used the back button the navigation bar appears in both A & B but if tapped the tabBarButton ,which causes the app to jump to screen A directly even from screen C, screen A will be missing the navigationBar.
I've check the self.navigatioController and it's initialized and has a value.
I've tried also to set the NavigationBarHidden property in the viewDidAppear but with no luck.
Any help on that issue? what may cause such a weird scenario?
Edit: Answer
I discovered the issue.
Screen C is a complex screen of a lot of containers.In one of the containers i was changing the navigationBar state and that affect everything else in the app and caused the weird behaviour and made me unable to control the state by myself.
Sorry for the trouble.
In both viewController A and viewController B, use this:
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden: NO animated:NO];
}
In viewController c, use this(as mentioned in question):
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden: YES animated:NO];
}
I discovered the issue.Screen C is a complex screen of a lot of containers.
in one of the containers i was changing the navigationBar state and that affect everything else in the app and caused the weird beahviour .
Try the following :-
[self.navigationController setNavigationBarHidden: YES animated:YES];
in place of :-
[self.navigationController setNavigationBarHidden: YES animated:NO];
Related
I've tried my app on iOS 7.1 and I found that the tab bar background disappears on a few occasions. I was able to track them down; it happens when:
pushing a view controller placed inside navigation controller (that is inside tab bar controller) with hidesBottomBarWhenPushed = YES
presenting a view controller and then dismissing it (i.e. the MFMailComposeViewController)
I've created a sample app (used the tab bar template + added button to display the view controller, and a mapView to be able to tell if the bar disappeared), and the issue is there.
Here is all the code for the sample app that I changed:
#import "FirstViewController.h"
#import MessageUI;
#interface FirstViewController () <MFMailComposeViewControllerDelegate>
#end
#implementation FirstViewController
- (IBAction)presentVCButtonPressed:(id)sender {
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailer = [[MFMailComposeViewController alloc] init];
mailer.mailComposeDelegate = self;
[mailer setSubject:#"Feedback for Routie"];
[mailer setToRecipients:#[#"support#routieapp.com"]];
[self presentViewController:mailer animated:YES completion:nil];
}
}
- (void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error {
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Here you can download the whole sample project.
Now, important thing: this seems not to affect iPhone 5, nor the simulator. The problem is on iPhone 4 and iPod Touch (last generation as of writing this post).
Does any of you have the same problem? Were you able to fix it?
Thanks!
Update: I found a workaround. See my answer below.
Fix found!
So after some investigating (and headache), I found out that there is a simple fix. Just toggle the translucent property, like this:
tabBar.translucent = NO;
tabBar.translucent = YES;
Now as for when to do this, there are several places for each case:
1) pushing viewController with hidesBottomBarWhenPushed = YESThe bar background disappears right after the pop animation finishes, so add the fix to the viewDidAppear: method of the viewController that presented it:
- (void)viewDidAppear:(BOOL)animated {
self.navigationController.tabBarController.tabBar.translucent = NO;
self.navigationController.tabBarController.tabBar.translucent = YES;
...
}
2) Presenting a view controller and then dismissing it:In this case, the tab bar background is already gone during the dismiss animation. You can either do it in each viewController that you present separately, or, if you have subclassed UITabBarController (like I have), you can add it into its viewWillAppear method. Just be aware that calling the fix right away won't help (I've tried); that's why I used the dispatch_after GCD function:
- (void)viewWillAppear:(BOOL)animated {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.tabBar.translucent = NO;
self.tabBar.translucent = YES;
});
...
}
I know this is not the cleanest way, but it's clearly bug on Apple's side, and it's likely to stay with us for a while (I assume there won't be any iOS 7.2, so we'll most likely be stuck with this until iOS 8 comes out).
It's been a while, so I'll re-iterate the issue. iOS 7 (on Device) Tab Bar becomes completely see-through on device, but works fine on Simulator. Appears to happen after hitting Back from a detail page that has hidesBottomBarWhenPushed enabled.
Setting the Tab Bar Controller > Tab Bar > Background to White Color in the Storyboard fixed it for me. This fix keeps the translucency intact.
For some reason, toggling tabBar.translucent off and on again in ViewDidAppear did not work for me.
Using Xcode 6.3.1 with Swift.
Go in your Main.storyboard and select your MKMapView to highlighted it (cf. in Navigator area you can select « Map View »). Then look carefully where is the bottom "white square": move it up the bottom bar!
In the size inspector, you can check where you place the « anchor » or view origin for this view (cf. top-left hand side in your project). This explains why it’s ok for iphone 5 which has a bigger height screen.
I use following method to disable the Navigation bar throughout the app:
[navcontroller setNavigationBarHidden:YES animated:YES];
But is it possible to disable it only for one ViewController?
Certainly. Whenever you enter a viewcontroller, you can enable or disable for that viewcontroller (just call [[self navigationController] setNavigationBarHidden:YES animated:YES] during viewWillAppear
The nicest solution I have found is to do the following in the first view controller.
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:NO animated:animated];
[super viewWillDisappear:animated];
}
This will cause the navigation bar to animate in from the left (together with the next view) when you push the next UIViewController on the stack, and animate away to the left (together with the old view), when you press the back button on the UINavigationBar.
Please note also that these are not delegate methods, you are overriding UIViewController's implementation of these methods, and according to the documentation you must call the super's implementation somewhere in your implementation.
Hopefully this will resolve your problem.
I am using following line of code:
[self.navigationController popViewControllerAnimated:YES];
But it is not behaving in ios 7 as it doing in ios 6.Some times it does not pop controller while we are pressing back button 2- 3 times in succession.
Resulting in abrupt behaviour in navigation bar and deallocating a controller but showing the same on ui .
So when we press anything on that controller it results to a crash since controller is already deallocated.
Check if you're running the code on the UI thread
[self.navigationController popToRootViewControllerAnimated:YES];
This method will navigate to the root of your navigationController.
You can check your viewController hierachy With following code.
NSLog(#"%#",self.navigationController.viewControllers);
I resolved this problem with this way:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UINavigationController * nav = tabbarControl.selectedViewController;
[nav.viewControllers objectAtIndex:0];
[nav setViewControllers:#[[nav.viewControllers objectAtIndex:0]] animated:NO];
tabbarControl.selectedIndex = 0;
});
When you delay one second the view will pop from UI, then the view will pop from the navigation stack, I think is the problem of the animation serial.
I had the same problem on iOS 8.
I solved by subclassing UINavigationController and adding this code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.delegate = self;
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
return [super popViewControllerAnimated:animated];
}
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
{
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
}
I basically block all the user interactions during the pop animation. I know it's a dirty solution, but it's the only one that I found that solves the problem.
I think that should be working without dispatch_async.
I got to the same issue, but i got to know the reason.
We should check it if the current scene is assigned to a proper view controller name in the storyboard.(identity inspector -> class)
If you connect a button action to m file and then insert the name of the view controller, that is not working.
So, you should delete the connect, and you insert the proper view controller name, and then you should connect the action to m file again.
I created my project from master-detail template, that uses split view controller. In my case, removing the split view controller resolved this issue.
It is important that that calls to popViewController(animated:), popToRootViewController(animated:) and related calls be made in the main queue, but under some conditions this doesn't seem to be good enough, and the animation doesn't occur.
I was able to fix it as described in some other answers here, performing the pop navigation later in the main queue. The Swift equivalent:
DispatchQueue.main.async {
self.rootViewController.popViewController(animated: true)
}
This might be explained by other animations that are still in progress, and by scheduling the block this way it happens at the end of the current work taking place or currently scheduled in the main queue, which allows the animation to execute correctly.
Try this code for popup a view controller from navigation stack
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count -2] animated:YES];
I have a uinavigationcontroller where i push a UIPageViewController with UIViewController1, UIViewcontroller2, ....!
I want to have the Navigationbar on UIViewController1, but not on the other UIViewController.
So on the first UIViewController1 i would have:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:NO];
}
and on the other UIViewController2, UIViewController3, ....
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController YES animated:NO];
}
Everything works fine when i move forward! But if i am sliding backward after moving from UIViewController3 to UIViewController2, suddenly the navigationBar already apperas on UIViewController2. I guess UIViewController1 is already appearing while i am looking on UIViewController2 and suddenly it gets the notification to show the UINavigationBar.
Putting the Commands into UINavigationBarDidAppear does not solve the problem :-(
Can Somebody help me out?
Found the answer. Actually everything works fine. I was just fooled by my Spaghetti Code i guess.
I didn't notice i already was hiding the navigationbar in the loadview method and then again in the viewWillAppear method. After removing the one in loadView its working perfectly!
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.