this is my question. I have three View Controllers (VC1, VC2 and VC3). Every View Controller inherited from UINavigationControllerDelegate and I delegate my navigation controller into the viewWillAppear method in this way:
self.navigationController.delegate = self;
And the only UINavigationControllerDelegate method that I use is for transition:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
animationControllerForOperation:(UINavigationControllerOperation)operation
fromViewController:(UIViewController *)fromVC
toViewController:(UIViewController *)toVC {
if (operation == UINavigationControllerOperationPush || operation == UINavigationControllerOperationPop) {
myTransitionController *transitionController = [[myTransitionController alloc] init];
return transitionController;
}else{
return nil;
}
}
My problem is this: when I walk from VC1 to VC2 and into this controller trigger a NSNotification, I execute popViewControllerAnimated to go back the previous View Controller (VC1). This is the code:
- (void) backToRoot: (id) sender{
[self.navigationController popViewControllerAnimated:YES];
}
and the UINavigationBar show correctly its appearance (UINavigationBar without back button). Then, when I walk from VC1 to VC2 until VC3, and programatically go back until VC1 with popToRootViewController, the transition of the views (VC3-VC2-VC1) it works perfectly, but the UINavigationBar appearance not update and it shows with back button in the VC1 (which is the root View Controller). The method in the VC3 that I implemented is this:
- (void) goToRoot{
[self.navigationController popToRootViewControllerAnimated:YES];
}
I have tried with a double call of popViewControllerAnimated, I added in viewWillAppear and viewDidAppear method into VC2 and It not works neither. Anyone have idea what happens?
According to the documentation the func Pops all the view controllers on the stack except the root view controller and updates the display but I can't figure out the problem. You can try with unwind segue, is really simple.
What are Unwind segues for and how do you use them?
Related
i have an app with three views:
FirstView
SecondView
ThirdView
When i am on the ThirdView and i click on the back button from navigation controller, i want to pass data from ThridView to SecondView.
But i don't know how to do this.
I don't want to add an extra button on my view.
The same when i'm on the SecondView and i want to go back to the FirstView.
I can't use the method "ViewWillDisappear" because if a set a "PerformSegueWithIdentifier" on this method to pass data from SecondView to FirstView, i can't switch to ThirdView because the "ViewWillDisappear" method will be executed.
Can you please help me?
PS: I use the language swift 2
In your viewWillDisappear or viewDidDisappear method you can check if back button is pressed by checking whether or not your view controller is moving from parent view controller.
override func viewWillDisappear(animated: Bool) {
if(self.isMovingFromParentViewController())
{
//Send data to previous view controller
print("Going back: Back button pressed");
}else{
print("Controller is hidden due to some other reason e.g Pushing another view controller");
}
}
I make subclass of UINavigationController because I cannot find Unwind Segue signature in UIViewController since Xcode 11.
#implementation CLUnwindNavigationController
- (BOOL)canPerformUnwindSegueAction:(SEL)action fromViewController:(UIViewController *)fromViewController withSender:(id)sender {
return NO;
}
- (IBAction)unwindForSegue:(UIStoryboardSegue *)unwindSegue towardsViewController:(UIViewController *)subsequentVC {
}
#end
You can find UnwindSegue signature.
You can connect to your desired action.
Currently I'm using Unwind to get to the Main View of its Path.
This is the code I've on the Sender ViewController:
- (IBAction)showRecents:(UIStoryboardSegue *)segue {
[self.navigationController.tabBarController setSelectedIndex:1];
NSLog(#"Root of Navigation Executed");
}
This is how it looks before unwinding
And this is how it looks after unwinding from the source view controller:
The issue is that I don't understand why it's not showing the Green TopBar? Has something to do with the TabBarController?
This is my Path VC:
The answer to this Question is to. First we need to Hide/Show the NavigationController on the Source ViewController and Before it disappear We need to Show it again. That Way on the Sender ViewController You will be able to see the Navigation Because it was set to be shown on the Source where the unwind its performed.
-(void)viewWillAppear:(BOOL)animated{
[self.navigationController setNavigationBarHidden:YES];
}
-(void)viewWillDisappear:(BOOL)animated{
[self.navigationController setNavigationBarHidden:NO];
}
I have a View Controller that has a custom push transition when a table cell is tapped and performs the standard pop transition when the back bar button item is tapped. The problem is when I try to go to the same view controller from the previous controller, the app crashes. Below is the UINavigationControllerDelegatefunction I'm implementing:
- (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC
{
return (operation == UINavigationControllerOperationPush ? animator : nil);
}
Any clue is appreciated!
Thanks in advance.
I had a problem, where the NavigationController's delegate was set to a view controller that had been deallocated, which caused a crash in [UINavigationController _customTransitionController:].
Especially when using unwind segues, it does NOT seem that any intermediate view controllers receive a viewWillDisappear callback before getting deallocated. The remedy here is to implement the following in the destination unwind view controller:
-(IBAction)unwindSegue:(UIStoryboardSegue*)segue{
self.navigationController.delegate = nil;
}
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];
}
}
}
From Home view - my RootViewController - I open up 2 ViewControllers one after another as user progresses in navigation hierarchy like so:
1) SecondViewController is pushed by button connected in my Storyboard
2) ThirdViewController is presented modally
[self performSegueWithIdentifier:#"NextViewController" sender:nil];
So, the picture is: RootViewController -> SecondViewController -> ThirdViewController
Now in my ThirdViewController I want to have a button to go back 2 times to my RootViewController, i.e. go home. But this does not work:
[self.navigationController popToRootViewControllerAnimated:YES];
Only this guy goes back once to SecondViewController
[self.navigationController popViewControllerAnimated:YES];
How can I remove both modal and pushed view controllers at the same time?
I had a similar situation, where I had a number of view controllers pushed onto the navigation controller stack, and then the last view was presented modally. On the modal screen, I have a Cancel button that goes back to the root view controller.
In the modal view controller, I have an action that is triggered when the Cancel button is tapped:
- (IBAction)cancel:(id)sender
{
[self.delegate modalViewControllerDidCancel];
}
In the header of this modal view controller, I declare a protocol:
#protocol ModalViewControllerDelegate
- (void)modalViewControllerDidCancel;
#end
And then the last view controller in the navigation stack (the one that presented the modal view) should implement the ModalViewControllerDelegate protocol:
- (void)modalViewControllerDidCancel
{
[self dismissViewControllerAnimated:NO completion:nil];
[self.navigationController popToRootViewControllerAnimated:YES];
}
This method above is the important part. It gets the presenting view controller to dismiss the modal view, and then it pops back to the root view controller. Note that I pass NO to dismissViewControllerAnimated: and YES to popToRootViewControllerAnimated: to get a smoother animation from modal view to root view.
I had the same requirement but was using custom segues between the view controllers. I came across with the concept of "Unwind Segue" which I think came with iOS6. If you are targeting iOS6 and above these links might help:
What are Unwind segues for and how do you use them?
http://chrisrisner.com/Unwinding-with-iOS-and-Storyboards
Thanks.
Assuming your AppDelegate is called AppDelegate, then you can do the following which will reset the rootviewcontroller for the app window as the view RootViewController
AppDelegate *appDel = (AppDelegate*)[[UIApplication sharedApplication] delegate];
RootViewController *rootView = [[RootViewController alloc] init];
[appDel.window setRootViewController:rootView];