I have fairly simple UINavigationControllers with two screens: screen1 & screen2.
When the user is on screen2 and clicks < Back I want to trigger an event before screen1 is shown -- basically I want to fetch data from the server for screen1.
Is there a way to do this?
In your viewDidLoad do this:
UIBarButtonItem *backBarButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:#"icon_back.png"] style:UIBarButtonItemStylePlain target:self action:#selector(goBack:)];
self.navigationItem.leftBarButtonItem = backBarButton;
Implement the method goBack:
- (void)goBack:(id)sender {
//Do something
[self.navigationController popViewControllerAnimated:YES];
}
Hope this helps.. :)
If you're using storyboard, you can handle your back action in.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Only by doing it in viewWillDisappear. Unfortunately it will be triggered also when you present a new screen over the current one, not just when you tap the back button. You could however add a custom back button, and place your code in it's action method. After the operation is finished, call [self.navigationController popViewControllerAnimated:YES]
-(void)viewWillDisappear:(BOOL)animated{
if (![self.navigationController.viewControllers containsObject:self]) {
NSLog(#"Back Event");
}
}
You can do in two way.
Create custom button and set event.
Check on viewWillDisappear when users pop the screen
Related
When a view loads, i want to see if it's because the user pressed the back button. How can i check this?
The best solution I've found to detect a UINavigationController's back button press (pre-iOS 5.0) is by verifying that the current view controller is not present in the in the navigation controller's view controller stack.
It is possibly safer to check this condition in - (void)viewDidDisappear:(BOOL)animated as logically, by the time that method is called it would be extremely likely that the view controller was removed from the stack.
Pre-iOS 5.0:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if (![[self.navigationController viewControllers] containsObject:self]) {
// We were removed from the navigation controller's view controller stack
// thus, we can infer that the back button was pressed
}
}
iOS 5.0+ you can use -didMoveToParentViewController:
- (void)didMoveToParentViewController:(UIViewController *)parent
{
// parent is nil if this view controller was removed
}
in your viewWillDisappear method check
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController]) {
//specific stuff for being popped off stack
}
}
This is only for post iOS 5
UINavigationController has a delegate property that issues delegate callbacks. Please see the iOS reference here.
The delegate doesn't have a "back button pressed" callback, but instead it tells you when something is going to appear on the navigation stack. When you press back, you are "popping" the top view controller off the stack, so it will tell you that the view is about to appear. I think this is the callback you'd be looking for.
You could have some simple logic to check if it's the view controller that's "interested", and then you could send a notification, et al.
For the sake of completeness, mix of two most upvoted answers (1, 2) in Swift:
override func willMoveToParentViewController(parent: UIViewController?) {
super.willMoveToParentViewController(parent)
if parent == nil {
// view controller is popping
}
}
This is a slightly different scenario, but I thought the solution might help others out.
In my situation, I had a UINavigationController within a UIPopoverController. I needed to detect whether the user clicked the back button, or clicked outside of the popover. To do this I checked the visibleViewController property in viewWillDisappear. If the view controller is still the visibleViewController when closing, then the popover is being closed by another means. If the view controller is not the visibleViewController when closing, then the back button was pressed.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.navigationController.visibleViewController != self) {
<Do something since we're closing using something else>
} else {
<Do something since we're closing because of the back button>
}
}
I tried using zach's solution, but isMovingFromParentViewController returns true for both cases.
I verified this works in iOS 5+
I hope this helps.
Create a custom back bar button and set the target,
Step 1: Add these methods to your class
- (void)backButtonClicked :(id)sender{
[self.navigationController popViewControllerAnimated:YES];
}
- (void)addBackBarButton{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, 0, 55, 35);
[button setTitle:#"back" forState:UIControlStateNormal];
[button addTarget:self action:#selector(backButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *customBarItem = [[UIBarButtonItem alloc] initWithCustomView:button];
self.navigationItem.leftBarButtonItem = customBarItem;
}
Step 2: Call [self addBackBarButton]; in viewDiDLoad method
You will get the action in backButtonClicked method. You can play around with it the way you want.
Cheers!
The only way to do this so you know for sure that it was the back button is to create a custom button. If you don't know how to do that, check out this tutorial. It won't look exactly like the normal back button, but close. If you need more help, post a comment
I am trying to find a way to stop some of the processes within a detail controller (and let the user know that this is happening) when the back button in the navigation bar is pressed. However, I can't find a way to implement these changes when the button is pressed.
Is there a way to do this?
If you want to raise a user alert/notification before going back, you are really going to have to create your own back bar button item and assign it to self.navigationItem.leftBarButtonItem.
You need to hide the default button using:
self.navigationItem.hidesBackButton = YES;
Then add a target to your new button which does your process cleanup and raises an alert. In the alert handler, pop the controller once the user has acknowledged the alert.
The fastest and easiest way is to use custom back button like below;
-(void)viewDidLoad{
UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStyleBordered target:self action:#selector(actionBack)];
[self.navigationItem setBackBarButtonItem:barButtonItem];
}
-(void)actionBack{
//PopViewController
}
Like any other button.
Put this in the .m file.
- (IBAction)saveButton:(id)sender {
//actions
}
Then control drag from the UINavigationBarButton to the IBAction
I want to prompt the user to save changes before they navigate back out of editing an entity in my IOS7 application.
An early stack overflow said I can detect this will happen at this point here: but I've been unable to abort the navigation.
-(void)willMoveToParentViewController:(UIViewController *)parent {
NSLog(#"\t\t\tThis VC has has been pushed popped OR covered");
if (!parent) {
NSLog(#"\t\t\tThis happens ONLY when it's popped");
}
}
basically if my managedObjectContext has unsaved changes I'd like to pop an alert box before the back navigation event happens. Any ideas?
I tried this solution: https://stackoverflow.com/a/19210888/2069812
but doesn't seem to work.
You can use custom back button and handle its touch event yourself. It's the simplest solution in this case.
For example:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Button" style: UIBarButtonItemStylePlain target:self action:#selector(buttonDidTouch:)];
- (void)buttonDidTouch:(id)sender)
{
if (edited) {
[self.navigationController popViewControllerAnimated:YES];
} else {
// Do your stuffs
}
}
I know my answer is not using -(void)willMoveToParentViewController:(UIViewController *)parent, but the easiest would be to just display no back button.
This can be done via:
self.navigationItem.hidesBackButton = YES;
You can also disable the swipe gesture as described here:
if ([self.navigationController respondsToSelector:#selector(interactivePopGestureRecognizer)]) {
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
But if you really want to hack in there then I would try a custom back button and handle the action in the controller.
I just made a custom button in IB and attached to it. Issue solved.
In my RecordViewController, within the didSelectRowAtIndexPath I push a detailViewController (which inherits from UIViewController):
[[self navigationController] pushViewController:detailViewController animated:YES];
Once the DetailViewController appears I can see a Back navigationButton in the top left corner, which automatically pops the current view controller to get back to the previous ViewController.
Now I need to show a UIAlertView and ask the user, if the data should be saved or not.
And only when the user has made a decision, the current view controller should disappear.
My problem is if I put this code into viewWillDisappear, it is already too late. I can't stop the process while showing the UIAlertView. This needs to be intercepted the moment the user pressed the back button.
Is there a method I could override to achieve this?
Create a UIBarButtonItem:
UIBarButtonItem * backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: #"Back"
style: UIBarButtonItemStyleDone target: self action: #selector(onBackButtonTapped:)];
Assign it to left bar button item:
self.navigationItem.leftBarButtonItem = backBarButtonItem;
Implement onBackButtonTapped API:
- (void) onBackButtonTapped: (id) sender
{
// Display an UIAlertView
}
You may want to customize the back button. Please look into UIBarButtonItem for more details.
Instead of pushing a detail view controller, the usual way to gather data is to present one modally. That will give you 2 free spaces on the left and right of the (new) navigation bar to place a Save and Cancel button.
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
[self presentViewController:navigationController animated:YES completion:nil];
// detailViewController will have to set up buttons in its init
You can use a delegate protocol you create to handle save and cancel actions in the presenting (i.e. not the detail) view controller.
Overview: The idea is to have your own barbutton to intercept the backing out from the VC.
In your viewDidLoad you can do this
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithTitle:#"Back"
style:UIBarButtonItemStyleDone target:self action:#selector(Back:)];
self.navigationItem.backBarButtonItem = backButtonItem;
Then your Back: method can do this
-(void)Back:(id) sender
{
//Your code for showing AlertView with delegate as self. Remember to conform to the UIAlertViewDelegate protocol.
}
Then put your save functionality in
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (selected buttonIndex is the one for saving data)
{
//save your data
}
//popViewController
}
I would like to call an action when my backButton is clicked but this doesn't seem to be it.
viewDidLoad in rootViewController:
self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc]
initWithTitle:#"Logout"
style:UIBarButtonItemStyleDone
target:self
action:#selector(logout)] autorelease];
The title of it is correct but nothing happens.
logout (in the rootViewController)
header:
-(void)logout;
body:
-(void)logout {
NSLog(#"test");
[[User owner] logout];
}
Could anyone tell me how to solve this, since i have no idea. Thanks
You can change only the title of backBarButton. You can try to use viewWillDisappear or viewDidDisappear functions but they could be called not only after you press your button. The leftBarButton is a better solution but this button's view differs from backBarButton's view.
The backBarButtonItem exists specifically to change the appearance of the back button. If you need a custom action, you should consider using leftBarButtonItem instead.