I have implemented a custom version of a search form that behaves a lot like a UISearchBar with a scope bar (but is actually pieced together programatically for UI reasons). The screen loads with a TextField, you tap in the TextField and the navigation bar animates up off the screen, the text field moves up and a segmented control appears for filtering results.
Anyway, that all works, but when I tap on one of the search results my code pushes a new ViewController. The problem is that new controller gets pushed without a navigation bar (because I used [[self navigationController] setNavigationBarHidden:YES animated:YES] when switching to the search state).
I can show the navigation bar as the new ViewController gets pushed, or even animate it in as the transition to the new ViewController appears - but all those solutions look clunky. I want it to work as if you were using a UISearchBar (actually more like the email app) in that the restored navigation bar appears to just slide in from the right as if it's part of the child view controller.
I'm hoping there'll be a simple fix... thanks
For anyone that comes to this, the solution is to make your controller the delegate of the UINavigationController, then show or hide the nav bar in your delegate methods.
Your controller needs to implement the protocol:
#interface MYSearchController() <UINavigationControllerDelegate>
Then in -(void)viewDidLoad assign your controller as the delegate:
[self navigationController].delegate = self;
Finally, implement a method like this:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if(viewController == self)
{
if(_searchState && ![self navigationController].navigationBarHidden)
{
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
}
else
{
if([self navigationController].navigationBarHidden)
{
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}
}
}
Related
I knew its a duplicate. But still having an issue and even when tried with possibilities didn't work. Hence posting the same to reach a solution. Hope to get help from you guys.
The initial is embedded inside UINavigationController. For the initial (the landing view) the navigation bar must be hidden. The other views when called from the landing view - must show the navigation bar.
I'm handling the hide & show of navbar in the landing view by overriding the methods of the view as follows:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Hiding the navigationbar hidden for the first page
[[self navigationController] setNavigationBarHidden:YES animated:YES];
}
// Even tried animated:NO & animated:animated
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
// Showing the navigationbar hidden for the first page
[[self navigationController] setNavigationBarHidden:NO animated:YES];
}
While the app loads initially, the nav bar is in hidden state (as expected & working fine). When coming back to the landing view from the child view controller, the nav bar gets hidden after some seconds - the landing view gets loaded on to the ui screen.
I also tried using the navigationcontroller delegate method in landing view: navigationController: willShowViewController: animated:. But unable to reach the solution that i need.
Hence i provided the navigationcontroller delegate in one of my childviewcontroller and checked whether the childcontroller when popped is not in viewcontrollers of the navigationcontroller using if condition. When yes, then i provided the hide option of the navigationbar. but also failed to have the solution.
During surfed, there was a solution to handle with viewanimation. I tried and that too failed.
Again surfed, the solution provided across is to handle the similar issue with viewwillappear & viewwilldisappear. I'm blinked since the way i'm doing is similar to the proposed way. Even then unable to reach a solution.
FYI.. I'm using Xcode 6.3 and deployment target is 6.0 onwards. I'm using storyboard to manage views.
Please help me sort the issue... App loads is hiding the nav bar in landing page. But when landing page is loaded back from a child view then the nav bar gets hidden only after the landing page loaded on to the ui. I do need to get hidden of the nav bar as like when app loads, when the child view pops and the landing view gets loaded on the top of the controller.
If you want to hide navigation bar in the second view then don't try to manage in viewWillAppear and viewWillDisappear because I have faced a lot of problems by trying like that and it also effected the constraints. Just use delegate for navigation controller in appDelegate it is working fine for me.
self.navigationController.delegate = self;
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if ([viewController isKindOfClass:[LoginViewController class]])
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
} else {
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
}
Use this method:
[navigationController setNavigationBarHidden:YES];
So, if you are in some view controller:
[self.navigationController setNavigationBarHidden:YES];
More clarifications:
UINavigationController has a property navigationBarHidden, that allows you to hide/show navigation bar for whole nav controller.
Let's look at the next hierarchy:
--UINavigationController
----UIViewController1
----UIViewController2
----UIViewController3
Each of three UIViewController will have nav bar since they are in UINavigationController. For example, you want to hide bar into the second (actually it doesn't matter in which one), then write into UIViewController2:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES]; //it hides
}
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO]; // it shows
}
Overwrite the delegate method in your custom UINavigationController class:
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
[self setNavigationBarHidden:NO];
if ([viewController isKindOfClass:[SomeViewController class]])
{
[self setNavigationBarHidden:YES];
}
}
One advantage for putting it in your UINavigationController class is that you don't clutter your UIViewController class with code
Tested and works.
UPDATE
Create a UINavigationController subclass: f.e. MyNavigationController
In AppDelegate.h:
#import "MyNavigationController.h"
#property (nonatomic) MyNavigationController *navigationController;
Then initialise it in AppDelegate.m:
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//Probably some more code here
self.navigationController = [[MyNavigationController alloc] initWithRootViewController:yourRootViewController];
self.window.rootViewController = self.navigationController;
self.window.backgroundColor = [UIColor blackColor];
[self.window makeKeyAndVisible];
return YES;
}
Then overwrite the delegate method in your custom UINavigationController class
I have little to no experience with storyboards so not really sure how to setup a custom UINavigationController, but this is how I do it in code.
Here's another SO post how to create a custom UINavigationController to use with storyboards.
I have two UIViewControllers, A and B.
A is hiding the UINavigationBar and B is not.
When animating (with the default animation) from A to B, the navigation bar has to become visible. The navigation bar just pops in at some point (viewWillAppear or viewDidAppear) instead of sliding in with the UIViewController B.
When going back from B to A, the navigation bar is smoothly sliding back out.
How can I achieve the desired effect when animating from A to B?
In ViewController B, one has to simply do:
-(void) viewWillAppear:(BOOL)animated {
[super viewWillAppear: animated];
[self.navigationController setNavigationBarHidden: NO animated: YES];
}
I wasn't aware that this also controls the animation while doing a full view controller transition. I thought it only controls animation the navigation bar out to the top and back in.
You can try the following:
Use a instance variable to do this:
self.navigationController setNavigationBarHidden:hide animated:animated];
_shouldHideStatusBar = hide;
And implement the following function:
- (BOOL)prefersStatusBarHidden{
return _shouldHideStatusBar;
}
The setNavigationBarHidden:animated function will automatically call prefersStatusBarHidden function. If it doesn't you can call it with the following UIViewController's method:
[self setNeedsStatusBarAppearanceUpdate];
And of course you can choose your status bar hiding animation style with:
- (UIStatusBarAnimation) preferredStatusBarUpdateAnimation {
return UIStatusBarAnimationSlide;
}
Let me know if this helps. Good luck!!
(I got this answer here: How to slide in/out statusBar and navigationBar simultaneously?)
Scenario
I have an app with a navigation controller. When the navigation controller pushes another controller onto the stack, in the upper left corner of the screen it shows the back button "<(title of the last view controller)".
What I need
I need something like (pseudo code)...
-(void)detectedBackButtonWasPushed {
NSLog(#"Back Button Pressed");
//Do what I need done
}
Question
Because this button is created by the navigation controller and I did not create this button in storyboards, how do I get the back button 'hooked up' to a method like this?
examples of what Ive tried for Oleg
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
UIViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"notification"];
if (viewController == vc) {
NSLog(#"BACK BUTTON PRESSED");
}
}
Is this how I'm supposed to do it? Cause this doesn't work.
Use viewWillDisappear to detect this.
-(void) viewWillDisappear:(BOOL)animated
{
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound)
{
[self backButtonPressed];
[self.navigationController popViewControllerAnimated:NO];
}
[super viewWillDisappear:animated];
}
-(void)backButtonPressed
{
NSLog(#"YEA");
}
Previously, I have solved this by setting the navigationBar leftItem to be a back button with a custom selector that dismisses the view along with whatever else it needed to do.
I might also suggest looking at the back button item and adding a target:self that is called on touch.
I am using UINavigationController to direct some view controllers.In some view controller, I don't want to use UINavigationBar, but in some others i may use. Now I am try to pop one view controller using UINavigationBar to its previous one which hide UINavigationBar. But when poped, there is one wired black space under screen. After you rotate the screen, the space will disappear.
the normal view controller A should be like this:
when press the text button, a view controller B will be pushed, which is as followings:
when click back button on the navigation bar. A will come out.but there is a black space at the bottom.
If rotate the screen, the space will disappear. And also in A's - (void)viewWillAppear:(BOOL)animated method i hide the navigationbar and let the screen autorotate.
- (void)viewWillAppear:(BOOL)animated
{
[self.navigationController setNavigationBarHidden:YES animated:animated];
[super viewWillAppear:animated];
[self willAnimateRotationToInterfaceOrientation:[UIApplication sharedApplication].statusBarOrientation duration:0];
}
whats wrong with this situation? Any help will be appreciated.
I add setNavigationBarHidden: method in the back button action method. it works. If i add this method in viewWillDisappear: method or others, it seems it doesn't work. The navigation bar will have effect on next appear view controller. which means, there will be a black space in the next view controller in the navigation stack.
Finally, i add a action method for the back button and setNavigationBarHidden:YES in the method, which is as follows:
- (void)backBtnClicked:(id)sender
{
[self.navigationController popViewControllerAnimated:NO];
[self.navigationController setNavigationBarHidden:YES];
}
I have a main view controller that lists a bunch of items, and when they tap on one of the items it segues them to the next view. However, in the next view, I don't want the navigation bar to be there, I only want it in the first view (I'm using a UIToolBar for the navigation bar, kind of like in iBooks).
How exactly do I go about achieving this? If I remove the main view controller from the navigation controller completely (unembedding, effectively) I can implement the nav bars selectively, but this solution doesn't allow segues, so it's no good.
My other solution was to call self.navigationController.navigationBarHidden = YES; in viewDidAppear for the second view, but with this, the UIToolBar that I added in my storyboard is pushed under the navigation bar that hasn't been hidden yet, and then when it does get hidden, it disappears and the UIToolBar "falls down", which is a pretty gross effect to the user.
What would be the best way to go about getting this effect?
The best way to do that is the following. In you viewWillAppear: in the first (rootViewController) of your UINavigationController, you set:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
and then in you viewWillDisappear, you the the opposite:
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
This way should work without nothing 'ugly' happening to the user.