Navigation bar back button method - ios

I want to navigate to the particular page in my application and i also dont want to create any custom back button for that.If I can override the method of the navigation bar back button so I can call the poptorootviewcontroller.so i can go to specific page. Anyone knows what is the method that is called by the navigation bar button and if we can use it?

You can try this.. Write your logic in this native method.
-(void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:YES];
// Your Code
}

You will have to provide the name and the implementation for the button method As there is no standard method ..
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(backButtonPressed)] autorelease];
implementation ..
-(void) backButtonPressed {
NSLog(#"Back button presses");
}

Try to use the below code:
NSArray * viewController = self.navigationController.viewControllers;
if([viewController count] > 3)
{
UIViewController * vc = [viewController objectAtIndex:0];
[self.navigationController popToViewController:vc animated:YES];
}

Related

UINavigation Bar being set by a different controller

What is happening in my app is that the user logs in and then the title of the controller becomes "Hello (Username)" and then the user presses a button and is pushed to a UITableViewController with the title: "Messages". After they select a message they are pushed to another UITableViewController, with the title "Message to (receiver)".
The problem is that when you press the back button on the 2nd UITableViewController that is titled "Message to (receiver), the title for the first UITableViewController becomes "Hello (Username)" instead of "Messages". This bug only happened when I updated to Xcode 6, and I have no idea what is causing it.
In ViewController 1 :
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIBarButtonItem *_backButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleDone target:nil action:nil];
self.navigationItem.backBarButtonItem = _backButton;
_backButton = nil; //This is to make the Back button on other viewController to read "Back"
}
-(void) viewDidLoad
{
[super viewDidLoad];
self.title = [[NSString alloc] initWithFormat:#"Hello %#", self.userLoggedIn];
//Hide backbutton
[self.navigationItem setHidesBackButton:YES animated:NO];
}
- (IBAction)messages:(id)sender
{
TableViewController *tableVC = [self.storyboard instantiateViewControllerWithIdentifier:#"checkForMessagesVC"];
[self.navigationController pushViewController:tableVC animated:YES];
}
In UITableViewController 1 :
-(void)viewDidLoad
{
self.title = #"Messages";
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
ViewMessagesVC *viewMessagesVC = [self.storyboard instantiateViewControllerWithIdentifier:#"viewMessagesVC"];
[self.navigationController pushViewController:viewMessagesVC animated:YES];
}
One more thing is that in ViewController 1 the back button is hidden. Then when you go to TableViewController 1 the back button shows, but when you go to TableViewController 2 and then go back to TVC 1 the back button is hidden. (Even if you put [self.navigationItem setHidesBackButton:NO animated:NO]; in the TableViewController's viewDidLoad the back button still won't show)
Not sure what is causing this, the only thing that is happening are pushes through a navigation controller and pressing the back button. There are timers and other things happening in each controller, but nothing effecting the title. Any ideas?
So hopefully nobody else foolishly runs into this weird error. For some reason the code in my 2nd TableViewController:
- (BOOL)prefersStatusBarHidden
{
return YES;
}
caused the error

How to navigate to some other View Controller when Navigation Controller back button is pressed?

I have a viewController in which, on the click of back button, I need to go to a specific viewController and call its method.So I created a barButton and added as a BACK button in navigation bar.When its selector is called I can see only see a black screen, nothing else.
Here how I am doing it.
In viewDidLoad
//Back Button in navigation Bar.
UIBarButtonItem *newBackButton = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(navigationBackButtonClicked:)];
self.navigationItem.leftBarButtonItem=newBackButton;
The selector below executes and shows a black screen.
-(void)navigationBackButtonClicked:(UIBarButtonItem *)sender {
SharedManager *sharedManagerObject = [SharedManager sharedInstance];
NSString *source = sharedManagerObject.toCityString;
NSString *destination = sharedManagerObject.fromCityString;
NSString *dateStr = sharedManagerObject.dateSelected_String;
BusListViewController *buslist_VC = [self.storyboard instantiateViewControllerWithIdentifier:#"BusListViewController"];
[buslist_VC getBusListForSource:source destination:destination date:dateStr];
[self.navigationController popToViewController:buslist_VC animated:YES];
}
You need to add your buslist_VC to the view hierarchy of your navigation controller before using [popToViewController:animated:]. This is used to display some viewcontrollers already in the stack of your navigation Controller.
Either way what you're asking might be a weird behaviour for your user but you can use :
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count - 1] animated:NO];
[self.navigationController pushViewController:buslist_VC animated:NO];
You cann't back to a new ViewController, you can push a new ViewController, in your code change this:
[self.navigationController pushViewController:buslist_VC animated:YES];
But keep in mind, you are putting this new viewController inside the other (where you are created a newBackButton), and the default back button come back to this. If you want to come back to the root use this:
[self.navigationController popToRootViewControllerAnimated:YES];
Or, now you can come back to any viewController on the navigation stack, this array:
NSArray *navStacks = self.navigationController.viewControllers;
Using popToViewController: be sure is in the stack.
You should use
NSArray *navStacks = self.navigationController.viewControllers;
select needed view controller and do
[self.navigationController popToViewController:selectedVC animated:YES];

Push to ViewController without back button

I am developing an iOS app which contains login/authentication functionality - basically first time a user logins, in they need to enter relevant login details - then they are passed to main app screens - subsequent visits to the app they will be automatically authenticated.
All above works fine - the issue I have is with the Navigation bar - it appears in the main screen in the main part of the app with a back button - I don't want this to be displayed as they should not be able to return to the login screen once authenticated. I guess it's using the root navigation controller which explains the logic, but is there a way to ignore the navigation controller of the login section so the back button is not displayed in the main app.
Below is a screenshot of the structure to help my explanation - left hand group of screens are the login process right hand is the main app structure.
The code used to switch screens is as follows -
SWRevealViewController *swRevealController = (SWRevealViewController *)navVC;
swRevealController.managedObjectContext = self.managedObjectContext;
[self.navigationController pushViewController:controller animated:YES];
Don't push view controller. Create new hierarchy with:
Objective-C
[self.navigationController setViewControllers:#[controller] animated:YES];
Swift
navigationController.setViewControllers([controller], animated:true)
In the Screen which implements after login, the ViewDidLoad method add the line to hide back bar button.
self.navigationItem.hidesBackButton = YES;
Additionally you can add an 'Logout' option as
UIBarButtonItem *backBarButton = [[UIBarButtonItem alloc] initWithTitle:#"Logout" style:UIBarButtonItemStyleBordered
target:self
action:#selector(LogoutClick)];
self.navigationItem.leftBarButtonItem = backBarButton;
-(void)LogoutClick {
[self showLogoutAlert];
}
-(void)showLogoutAlert {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#""
message:#"Do you want to Logout ?"
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Logout", nil];
[alert show];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 1) {
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
Use a modal view controller for the login screen so its not part of your navigation controller hierarchy within your navigation root probably in view did load - sample code below:
- (void) viewDidLoad {
......
LoginVC *loginViewController = [LoginVC alloc] init];
loginViewController.parent = self;
[self presentViewController: loginViewController animated:YES completion:NULL];
return;
}
You may or may not dismiss the modal view from the root - if you do, you will need to be able to call the dismiss routine from loginViewController but there are other ways as well and you can put the dismiss inside the modal view (loginViewController)
(void) login_exit:(BOOL)success {
[self dismissViewControllerAnimated:YES completion:NULL];
if !(success) {
.... send message (UIAlertview and ask if he or she wants to try again)
}
else {
}
return;}
Very simple.. Just navigate to rootviewcontroller
SWRevealViewController *swRevealController = (SWRevealViewController *)navVC;
swRevealController.managedObjectContext = self.managedObjectContext;
//-- I think above lines not needed as per your question
[self.navigationController popToRootViewControllerAnimated:YES];
You need to hide the Navigation Bar in the ViewController before you push the SWRevealViewController by using the below line in viewDidLoad
Objective C
self.navigationController.navigationBarHidden = true;
Swift
self.navigationController?.navigationBarHidden = true;
It will not show the back button in the next view controller pushed
2022 answer
#IBAction func SomeScreen() {
let s = UIStoryboard ...
navigationController?.isNavigationBarHidden = true;
navigationController?.pushViewController(s, animated: true)
}
It's that easy.
Write this in viewDidLoad method
self.navigationItem.hidesBackButton = YES;
This will hide the back button for the first view.
ClassA* controller = [storyboard instantiateViewControllerWithIdentifier:#"ClassAIdentifier"];
if (controller != nil) {
[self.navigationController pushViewController:controller animated:YES];
[controller.navigationItem setHidesBackButton:YES animated:NO];
}
You MUST hide the navigationItem after push, otherwise it will be nil.

UINavigationController and back button action

I have an two controllers 1st is self and 2nd is maincontroller, where I'm pushing maincontroller in stack, so the back button is automatically coming.
Here I need to make an alert when the user presses the back button.
How can I do this?
Or you can use the UINavigationController's delegate methods. The method willShowViewController is called when the back button of your VC is pressed.
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
First hide the back button by using
self.navigationItem.hidesBackButton = YES;
and then create your own Custom Button:
UIBarButtonItem *backBtn =[[UIBarButtonItem alloc]initWithTitle:#"back" style:UIBarButtonItemStyleDone target:self action:#selector(popAlertAction:)];
self.navigationItem.leftBarButtonItem=backBtn;
[backBtn release];
and your selector is here:
- (void)popAlertAction:(UIBarButtonItem*)sender
{
//Do ur stuff for pop up
}
Best and Easiest way
Try putting this into the view controller where you want to detect the press:
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
// back button was pressed. We know this is true because self is no longer
// in the navigation stack.
}
[super viewWillDisappear:animated];
}
Create your own UIBarButtonItem and set it as the leftBarButtonItem in viewDidLoad method of mainController.
For example (here I used a system item but you can also create a different one, see class reference for details).
UIBarButtonItem *leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(showAlertView:)];
self.navigationItem.leftBarButtonItem = leftBarButtonItem;
// only if you don't use ARC
// [leftBarButtonItem release];
where
- (void)showAlertView:(id)sender
{
// alert view here...
}
add a custom back button with an action and set your alert in that action method.You can add your custom back button from here: http://www.applausible.com/blog/?p=401
viewControllerCount - is the var that holds the number of viewControllers previously was in the UINavigationController. Then, we check if viewControllerCount > [viewControllers count] if so, we know that we will get back (i.e. Back button imitation).
- (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
NSArray *viewControllers = [navigationController viewControllers];
if (viewControllerCount > [viewControllers count])
{
// your code
}
viewControllerCount = [viewControllers count];
}
extension ViewController: UINavigationControllerDelegate {
// when the self != viewcontroller ,it's mean back
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if self != viewController {
// your code
}
}}
create a button and give the button action as follows.
[self alert];
and when the alert is displayed, after tapping over yes
[self.navigationController popViewController];
after this,
self.navigationController.LeftBarButton = myButton;
this may help

How to trap the back button event

I have a UITableViewController that launches a UIViewController and I would like to trap whenever the back button is pressed in the child controller, which is the class that derives from 'UIViewController'. I can change the Back Button title but setting the target & action values when setting the backBarButtonItem seems to get ignored. What's a way to receiving some kind of notification that the Back button was tapped?
- (void)showDetailView
{
// How I'm creating & showing the detail controller
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyDetailView" bundle:nil];
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"Pages"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(handleBack:)];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];
[self.navigationController pushViewController:controller animated:animated];
[controller release];
}
- (void)handleBack:(id)sender
{
// not reaching here
NSLog(#"handleBack event reached");
}
You can implement the viewWillDisappear method of UIViewController. This gets called when your controller is about to go away (either because another one was pushed onto the navigation controller stack, or because the 'back' button was pressed).
To determine whether the view is disappearing because of the back button being pressed, you can use a custom flag that you set wherever you push a new controller onto the navigation controller, like shown below
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (viewPushed) {
viewPushed = NO; // Flag indicates that view disappeared because we pushed another controller onto the navigation controller, we acknowledge it here
} else {
// Here, you know that back button was pressed
}
}
And wherever you push a new view controller, you would have to remember to also set that flag...
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
...
viewPushed = YES;
[self.navigationController pushViewController:myNewController animated:YES];
...
}
It has been a while since this was asked, but I just tried to do this myself. I used a solution similar to Zoran's, however instead of using a flag I did this:
- (void)viewWillDisappear: (BOOL)animated
{
[super viewWillDisappear: animated];
if (![[self.navigationController viewControllers] containsObject: self])
{
// the view has been removed from the navigation stack, back is probably the cause
// this will be slow with a large stack however.
}
}
I think it bypasses the issues with flags and IMO is cleaner, however not as efficient (if there are lots of items on the navigation controller).
In my opinion the best solution.
- (void)didMoveToParentViewController:(UIViewController *)parent
{
if (![parent isEqual:self.parentViewController]) {
NSLog(#"Back pressed");
}
}
But it only works with iOS5+
I use this code:
- (void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound)
{
// your view controller already out of the stack, it meens user pressed Back button
}
}
But this is not actual when user presses tab bar button and pops to root view controller at one step. For this situation use this:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(viewControllerChange:)
name:#"UINavigationControllerWillShowViewControllerNotification"
object:self.navigationController];
- (void) viewControllerChange:(NSNotification*)notification {
NSDictionary* userInfo = [notification userInfo];
if ([[userInfo objectForKey:#"UINavigationControllerNextVisibleViewController"] isKindOfClass:[<YourRootControllerClass> class]])
{
// do your staff here
}
}
Don't forget then:
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"UINavigationControllerWillShowViewControllerNotification"
object:self.navigationController];
You can make your own button and place it as the leftBarButtonItem. Then have it call your method where you can do whatever, and call [self.navigationController popViewController... yourself
{
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:#"back"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(handleBack:)];
self.navigationItem.leftBarButtonItem = backButton;
[backButton release];
[self filldata];
[super viewDidLoad];
}
just replace backBarButtonItem with leftBarButtonItem
Simply use viewDidDisappear instead. It will be perfectly called in any scenario.
We are basing your lifecycle management on viewDidAppear and viewDidDisappear. If you know Android: the both are comparable to onResume and onPause methods. But there is a difference when it comes to locking the screen or pressing the homebutton on iOS.

Resources