I am trying to detect when the user pressed the back button in a GLKViewController. The view controller is presented via a storyboard from the root view controller (which is a menu).
The problem is that I cannot detect when the back button is pressed (so I can free up memory).
I have tried :
if (self.isMovingFromParentViewController) {
// Do your stuff here
NSLog(#"Dismissed");
}
And
if (self.isBeingDismissed) {
// Do your stuff here
NSLog(#"Dismissed");
}
Neither of which fires. Can anyone suggest why ?
you could make your own action to BackButton:
[self.navigationItem.backBarButtonItem setAction:#selector(action:)];
-(void) action:(id)sender {
//do something here
[self.navigationController popViewControllerAnimated:YES];
}
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 want to perform some code when the segue goes back one step. For example, when the back button gets selected, I want to perform some code.
I can't create a new unwind action from the back button because there is no back button in the storyboard. Is there a way to insert code, as soon as the back button is selected?
If you want to stick with the default back button, one way to do this is to subclass the navigation controller, and override popViewControllerAnimated: which is called when you tap the back button.
-(UIViewController *)popViewControllerAnimated:(BOOL)animated {
UIViewController *vcToBePopped =[super popViewControllerAnimated:animated];
id vc = self.viewControllers.lastObject; // this will be the controller you're going back to
if ([vc isKindOfClass:IntendedViewController class]) { // replace IntendedViewController with the actual class name you care about
[(IntendedViewController *)vc someMethod];
}
return vcToBePopped;
}
Is there a way to tell if a new controller came from a navigation back button or was pushed onto the stack? Id like to reload data only for pushing on the navigation stack, not on a back button press.
As of iOS 5.0 you can do this:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if (self.isBeingPresented || self.isMovingToParentViewController) {
// "self" is being shown for the 1st time, not because of a "back" button.
}
}
If your push also includes instantiating the view controller, put your push-only logic in viewDidLoad. It will not be called on back because it has already been loaded.
You could implement the UINavigationControllerDelegate and override the `navigationController:didShowViewController:animated:' method. You'll then have to check the returned view controller to make a determination as to whether you came back from the expected view controller.
- (void)navigationController:(UINavigationController*)navigationController didShowViewController:(UIViewController*)viewController animated:(BOOL)animated
{
if (yourPushedViewController == viewController)
{
// Do something
}
}
Let me explain. I have multiple UIViewControllers. On my MainPageController, I have 3 UIViews. Let's enumerate it this way: the first UIView is called LoginView, the second is called HomeView and the other one is called RegView. Now in HomeView, there are multiple buttons that will lead to other UIViewControllers. For example, one button will lead to StoreController. Now if I am inside StoreController and I want to go back to MainPageController, I simply call:
[self dismissModalViewControllerAnimated:YES completion:nil]
This will send me back to the HomeView.
That is good. However, inside the StoreController, there are buttons which will supposedly direct me to LoginView or RegView, whichever button was tapped. The problem is when the method [self dismissModalViewControllerAnimated:YES completion:nil], it only take me back to HomeView, no matter which button I pressed.
So how will I display the right UIView once the dismissModalViewControllerAnimated is called?
EDIT:
This is how I show the UIViews:
-(void)viewDidLoad
{
//Initialize the views here...
}
-(void)showViewByTag:(NSInteger)tag
{
if (tag == 1)
{
[self.view addSubview:loginView];
}
else if (tag == 2)
{
[self.view addSubview:homeView];
}
else
{
[self.view addSubview:regView];
}
}
Now I call the method showViewByTag: somewhere in my code to display the views.
What you could try and do is following: before calling [self dismissModalViewControllerAnimated:YES completion:nil] (and thus go back to your home view), change the view currently displayed in your MainPageController:
[(MainPageController*)self.presentingViewController showViewByTag:desiredViewTag];
[self dismissModalViewControllerAnimated:YES...];
If you are worried at the cast and you foresee that self.presentingViewController might be not of MainPageController type on some occasions, then you can check explicitly for its type:
if ([self.presentingViewController isKindOf:[MainPageController class]])
[(MainPageController*)self.presentingViewController showViewByTag:desiredViewTag];
[self dismissModalViewControllerAnimated:YES...];
For this to compile, MainPageController.h must be imported in your modal controller class.
dismissModalViewController will always bring back the viewController which presented it ,and that can be only one,so the ideal way would be to tell the navigationController to initWith your desired viewController..
eg on regButton click in the presented modalview
RegViewController *regViewController = [[RegViewController alloc]initWithNibNam:#"RegViewController" bundle:nil];
[self.navigationController initWithRootViewController:regViewController];
Hi there, Now I'm trying to create a Pop-OverView using an Xcode
storyboard. Firstly, I have
rootViewController, UIViewController, and UITableViewController
I want the UIView to act as a page flip and the UITableView will show popOver under the navigationBar item controller.
For the UITableView, I want to make a Pop-Over under NavigationBar controller. The problem is, when I touch the Navigation item to show the UITableViewController, it shows correctly, but when I try to close the Pop-Over View, it won't close. And then, the navigation item doesn't work well. It shows multiple instances of popOverView when I touch it multiple times.
This doesn't seem to make sense to me. Can anyone help me out or tell me where to find documentation / tutorials on this?
UPDATE:
For the UIPopOverController, it seems to work well now, but it is still bugging me when I touch a Navigation Item multiple times. It will show multiple instances of PopOver. How can I handle it, so it will show only one instance?
I had the same problem and mostly found the solution here. Basically you change the action of the button each time it's pressed to either display or dismiss the popover. Here's the code I ended up with:
#interface FilterTableViewController : UITableViewController {
UIPopoverController *editPopover;
id saveEditSender;
id saveEditTarget;
SEL saveEditAction;
}
-(void)prepareForSegue:(UIStoryboardPopoverSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"EditFilterSegue"]){
// Save the edit button's info so we can restore it
saveEditAction = [sender action];
saveEditTarget = [sender target];
saveEditSender = sender;
// Change the edit button's target to us, and its action to dismiss the popover
[sender setAction:#selector(dismissPopover:)];
[sender setTarget:self];
// Save the popover controller and set ourselves as the its delegate so we can
// restore the button action when this popover is dismissed (this happens when the popover
// is dismissed by tapping outside the view, not by tapping the edit button again)
editPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
editPopover.delegate = (id <UIPopoverControllerDelegate>)self;
}
}
-(void)dismissPopover:(id)sender
{
// Restore the buttons actions before we dismiss the popover
[saveEditSender setAction:saveEditAction];
[saveEditSender setTarget:saveEditTarget];
[editPopover dismissPopoverAnimated:YES];
}
-(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
// A tap occurred outside of the popover.
// Restore the button actions before its dismissed.
[saveEditSender setAction:saveEditAction];
[saveEditSender setTarget:saveEditTarget];
return YES;
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// Before we navigate away from this view (the back button was pressed)
// remove the edit popover (if it exists).
[self dismissPopover:saveEditSender];
}