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.
Related
I have a subclass of UINavigationController that has maximum of 4 ViewControllers in the stack. Lets call them firstVC ... fourthVC. My NavController can perform custom transitions between VCs and ios7/8 back gesture is supposed to be disabled and enabled depending on which VC is currently at the top of the stack. I've set my root VC (firstVC) as a NavController's delegate and trying to enable/disable back gesture in the delegate's method
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if ([viewController respondsToSelector:#selector(needsBackGestureEnabled)]) {
[self.navigationController.interactivePopGestureRecognizer setEnabled:YES];
NSLog(#"Back gesture enabled");
self.navigationController.interactivePopGestureRecognizer.delegate = (id<UIGestureRecognizerDelegate>)self;
} else {
if ([navigationController.interactivePopGestureRecognizer isEnabled]) {
[self.navigationController.interactivePopGestureRecognizer setEnabled:NO];
NSLog(#"Back gesture disabled");
self.navigationController.interactivePopGestureRecognizer.delegate = nil;
}
}
}
It works like a charm except one glitch. I feel like a short scheme might explain situation better:
FirstVC -[CustomTran]-> SecondVC -[push]-> ThirdVC -[push]-> FourthVC
FourthVC is the only one that have -needsBackGestureEnabled selector, but after transition from second to third back gesture gets enabled by itself. Even though the back button is susbtituted with the CustomBarButtonItem. I feel like performing default -pushViewController animation makes back gesture enabled somehow. I tried to ecplicitly disable it in my NavController subclass in -pushViewController but it didn't change a thing. Any idea why this is happening and how to fix this?
So I was create three UITableViewControllers with UINavigationController. I want a back button on 3rd UITableViewController, what returns my view to first UITableViewController instead of second.
How can I do that? That must be a real backButton, not a image or something else. Will be perfect to do this only with storyboard.
UPDATE
Perhaps I poorly explained what I want.
I don't want use any button with action on it. I just want something like as setting "address" of 1st TableViewController on my default back button. There is any way to do it?
add a button and connect it to following action
- (IBAction)backToFirstView:(UIButton *)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
(or)
[self.navigationController popToViewController:yourFirstViewControllerObject animated:YES];
}
There are different ways to navigate from DetailViewController to other view controllers.
We will go through the cases one by one.
First of all I would like to clear that if its your default
navigation bar's back button, then it must return to the last most
view controller only which is actually a default behavior of a
navigation controller.
Second, If you would like to go back to the
last most view controller on the tap of a button placed by you, you
should write the following code
[self.navigationController popToViewController:NAME_OF_A_VIEWCONTROLLER animated:YES];
Third, If you would like to go to the first view controller from where you
started, you should write the following code
[self.navigationController popToRootViewControllerAnimated:YES];
Ok, I found a way to resolve my problem. Thanks for your answers guys, they was very helpful.
So for resolve this problem you just need use link what give me Kumar KL upper, and wrote next method in your UITableVIewController
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
// Navigation button was pressed. Do some stuff
[self.navigationController popViewControllerAnimated:NO];
}
[super viewWillDisappear:animated];
}
Now you got a backButton what redirect you to your viewController, BUT title of this button is wrong. Let's resolve that unfair.
Create new class CustomSegueцрфе inherited from UIStoryboardSegue with next code in CustomSegue.m :
- (void)perform
{
UIViewController *sourceView = (UIViewController *) self.sourceViewController;
UIViewController *destinationView = (UIViewController *) self.destinationViewController;
[[destinationView navigationItem] setTitle:#"TitleOfYourViewController" ] ;
[sourceView.navigationItem setTitle:#"TitleOfButton"] ;
[sourceView.navigationController pushViewController:destinationView animated:YES];
}
Now you can go to storyboard and connect 2nd ViewController with 3rd with custom segue.
Like you see UINavigationController uses Title of previous ViewController for button title, so you just need change it.
Here is my setup:
App launches with a main screen that has 4 buttons. each button takes you to a new view/childview. Each child view has a back button( via navigation controller) to take you back to the main/menu screen. Easy enough. And works great. however, here is what i want to do:
Main screen has 4 buttons to 4 different views. On the main screen all you see is the main page/menu, NO TABBAR. However, when you go to any of the 4 view options a tab bar will be present that is populated with tabs to the 4 child views. AND there will also be a navigation bar if we wanted to go back to the Main menu.
So essentially: Main Menu shows NO TAB BAR. 4 child views show Tab Bar AND navigation bar. I messed around with a bunch of stuff but can't get it to work. Any thoughts about how to do this?
You can achieve this by having your storyboard look like this:
Then in YourMainMenuViewController's implementation:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UITabBarController *tabVC = segue.destinationViewController;
if ([segue.identifier isEqualToString:#"Tab1"]) {
tabVC.selectedIndex = 0;
}
else if ([segue.identifier isEqualToString:#"Tab2"]) {
tabVC.selectedIndex = 1;
}
else if ([segue.identifier isEqualToString:#"Tab3"]) {
tabVC.selectedIndex = 2;
}
else if ([segue.identifier isEqualToString:#"Tab4"]) {
tabVC.selectedIndex = 3;
}
}
Although I advise against putting a tab bar controller inside a navigation controller like this as it's kind of confusing UI.
To show navigationBar on viewWillAppear implement this
[self.navigationController setNavigationBarHidden:NO];
To show tabBar on viewWillAppear implement this
self.tabBarController.tabBar.hidden = NO;
You can set them YES to make them hidden in your menu on viewWillAppear
Hope it helps
I would like to display an image in response to a local notification event that occurs while the iPhone is locked. When the user swipes on the notification, I would like my app to go to the root view controller, via popToViewController:animated, and then push a view controller that displays the image. This works when I set animated = YES. When animated = NO, the view controller that displays the image doesn't respond when the user taps the back button. Any thoughts on why the image view controller's navigation controls don't work when I popToViewController without animation? Thanks in advance.
Here's the relevant code...
- (void) localNotificationHandler
{
#ifdef kAnimatePop
animated = YES; // This works
#else
animated = NO; // This doesn't work
#endif
_showImage = YES;
// Check if this view controller is not visible
if (self.navigationController.visibleViewController != self) {
// Check if there are view controllers on the stack
if ([self.navigationController.viewControllers count] > 1) {
// Make this view controller visible
[self.navigationController popToViewController:self animated:animated];
}
}
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (_showImage) {
_showImage = NO;
// Show image in a view controller
[self performSegueWithIdentifier:#"MainToImageSegue" sender:self];
}
}
You don't set _showImage until after popToViewController has been invoked. If it's animated viewDidAppear won't be called until later, so it unexpectedly works. If it's not animated then viewDidAppear is called immediately, before _showImage has been set. Move _showImage = true; to before the nav controller stack manipulations.
I might do the check this way:
- (void) localNotificationHandler{
...
...
if (self.navigationController.topViewController != self) {
[self.navigationController popToRootViewControllerAnimated:NO];
}
}
I would also recommend pushing your image view controller programmatically with something like
[self.navigationController pushViewController:<imageVC> animated:YES];
If your image view controller's navigation buttons are not working, it is likely because it is sending those navigation messages to nil. aka, the imageViewControllers self.navigationController is equal to nil.
I'm not sure how to fix this with storyboards, but if you present it programatically that problem should go away.
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];
}
}
}