In my story board I have:
NavController-> View1(root) -> View2 ->View3 ->View4
I can normally use the flow in that order and navigation between segues is easy.
But How to go from View1 to View4 .. and from View4 there is back button should take you to View3?
Because if I made direct Segue From View1 to View4 ,, I cant reach View3.
Please let me know how to do this. Thanks in advance.
Here is an example with 3 viewcontrollers only but it will be the same logic:
You need to create segue between viewcontrollers like this:
viewController1 --- segueFrom1To2 ----- viewController2
viewController1 --- segueFrom1To3 ----- viewController3
viewController2 --- segueFrom2To3 ----- viewController3
Then you need a property in your viewController2, let's say: goToNextVc;
So, in your viewController1, you will be able to set this property when your perform the appropriate segue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
ViewController2 *vc2 = segue.destinationViewController;
if ([segue.identifier isEqualToString:#"segueFrom1To3"])
{
vc2.goToNextVc = YES;
}
else{
vc2.goToNextVc = NO;
}
}
And now in the viewWillAppear of viewController2, simply add:
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
if (self.goToNextVc){
self.goToNextVc = NO;
[self performSegueWithIdentifier:#"segueFrom2To3" sender:self];
}
}
If you don't want to see the transition between viewController1 and viewController2, simply create a custom segue, let's say SegueNoTransition in which you need to override perform:
-(void) perform{
[[[self sourceViewController] navigationController] pushViewController:[self destinationViewController] animated:NO];
}
And replace the type "show" of segueFrom1To3 with "custom" and the class with SegueNoTransition;
for (UIViewController *controller in self.navigationController.viewControllers) {
if ([controller isKindOfClass:[yourViewController class]]) {
[self.navigationController popToViewController:controller
animated:YES];
}
else {
NSLog(#"Not Found");
}
}
// You must import the viewController where you want to move.
// yourViewController = viewController where you want to go in example.
Related
I have three Viewcontrollers : ViewControllerA, ViewControllerB and ViewControllerC.
When I am in ViewControllerC, I click on Navigation Back button to go back to ViewControllerA directly, skipping ViewControllerB.
I have tried following approaches, both of them work. But, I wonder while transiting from ViewController C to ViewController A, it shows ViewController B in one second for during the transition.
Is there a way just directly navigate from ViewController C to ViewController A skipping ViewControllerB.
Approach 1:
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
NSLog(#"back button pressed");
[self.navigationController popViewControllerAnimated:YES];
}
[super viewWillDisappear:animated];
}
Approach 2:
-(void) viewWillDisappear:(BOOL)animated {
if ([self.navigationController.viewControllers indexOfObject:self]==NSNotFound) {
NSLog(#"back button pressed");
//[self.navigationController popViewControllerAnimated:YES];
NSMutableArray *allViewControllers = [NSMutableArray arrayWithArray:[self.navigationController viewControllers]];
for (UIViewController *aViewController in allViewControllers) {
if ([aViewController isKindOfClass:[ViewControllerA class]]) {
[self.navigationController popToViewController:aViewController animated:NO];
}
}
}
[super viewWillDisappear:animated];
}
You need to use setViewControllers method, and pass only the viewControllerA that is the first element in your navigationController.viewControllers array
Code
- (IBAction)backAction:(id)sender {
UIViewController * viewControllerA = [self.navigationController.viewControllers firstObject]; //we get the first viewController here
[self.navigationController setViewControllers:#[viewControllerA] animated:YES];
}
similar answer here How to start from a non-initial NavigationController scene but in swift
Try popToRootViewControllerAnimated . It will move to First ViewController which NavigationController embed.
[self.navigationController popToRootViewControllerAnimated:YES];
NSArray *arrayViewControllers = [self.navigationController viewControllers];
for (UIViewController *viewcontroller in arrayViewControllers) {
if ([viewcontroller isKindOfClass:[ViewControllerA class]]) {
[self.navigationController popToViewController:viewcontroller animated:true];
}
}
There are five controllers here, AViewController, BViewController, CViewController,DViewController,EViewController,controllers here,
A present---> B
B present---> C
C push--->D
D push--->E
Now, if I want to go back from EViewController to AViewController in one step, what code should I write?
[self.navigationController popToRootViewControllerAnimated:animated];
1) Getting the desirable ViewController as Below
for (id controller in [self.navigationController viewControllers])
{
if ([controller isKindOfClass:[AViewController class]])
{
[self.navigationController popToViewController:controller animated:YES];
break;
}
}
2) Here you have A,B,C,D,E Controllers. means A would be on 1 Position so what can you do
you can hard wired the Index as Below
[self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:0] animated:YES];
3) Pop to the first viewController or rootViewController
[self.navigationController popToRootViewControllerAnimated:animated];
Use unwind segues.
In AViewController add bellow code
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
}
Go to User Interface of EViewController and Ctrl-drag from the button (you want set action) to the “Exit” outlet, you will see a modal popup.
You can do it recursively with generic solution. First of all you should have reference to A's navigation controller and then you should write recursive method to get active navigation controller like :`
-(UINavigationController*)getActiveNavigationController : (UINavigationController*)navigationController {
if ([navigationController.presentedViewController isKindOfClass:[AViewController class]]) {
return [self getActiveNavigationController:(UINavigationController*)((AViewController*)navigationController.presentedViewController)
];
}
if ((UINavigationController*)navigationController.presentedViewController == nil) {
return navigationController;
}
return [self getActiveNavigationController:(UINavigationController*)navigationController.presentedViewController];
}
`
After that you should write method like
-(void)getInitialScreen:(UINavigationController*)AViewControllerNavigationController {
if ([AViewControllerNavigationController.presentedViewController isKindOfClass:[AViewController class]]) {
return;
}
UINavigationController *navigation = [self getActiveNavigationController:AViewControllerNavigationController];
[navigation dismissViewControllerAnimated:YES completion:^{
[self getInitialScreen:AViewControllerNavigationController];
}];
}
finally after you wrote those 2 methods. You can call them like below and you can always get AViewController
[self getInitialScreen:AViewControlelrnavigationcontroller];
[AViewControlelrnavigationcontroller popToRootViewControllerAnimated:YES];
So I have a problem when trying to push some Viewcontrollers basically when the app loads it checks if you are already registered and if you are it sends you to a diff vc and if your not registered it sends you to a RegisterVC. It's done in storyboard and the problem is that when I put the code in viewDidLoad the pushes works but I can't see the rootviewcontroller from the storyboard but if I move the code into the init with coder I can see the viewcontroller but the push return's nil in the method that's supposed to push to a new vc, so the transition never happens.
The code looks like follows:
if (emp == nil) {
[self gotoRegisterView];
}
else {
[self gotoSMWView];
}
and :
- (void) gotoRegisterView {
UIViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"RegisterVC"];
[self.navigationController pushViewController:vc animated:YES];
}
- (void) gotoSMWView {
UIViewController* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"SMWVC"];
[self.navigationController pushViewController:vc animated:YES];
}
Any suggestions are much appreciated.
If you're using storyboards, just connect the main scene to any other scene you want to call from there. Then, Ctrl+Drag from the initial VIEW CONTROLLER (not elements on the view controller, but from the controller itself). Then click on the segues you just created and give them good descriptive names. For this example, we'll just say segue1 and segue2.
Now, if segue1 takes you to the RegisterView, and segue2 to SMWView then you can do this:
- (void) gotoRegisterView {
[self performSegueWithIdentifier:#"segue1" sender:self];
}
- (void) gotoSMWView {
[self performSegueWithIdentifier:#"segue2" sender:self];
}
If you need to do any other initialization or set up on these view controllers, you can override this method:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
Within this method, you can check which segue has been called using this template:
if([[segue identifier] isEqualToString:#"segue1"])
And you can get an instance of your destination view controller like this:
YourViewController *vc = [segue destinationViewController];
I have a storyboard with a UINavigationController. The root view controller of the navigation controllers is called rootViewController.
I am trying to programmatically change the view controller (depending on other conditions) to another view controller called loginViewController.
I am trying to do this in the viewDidLoad from the rootViewController like this:
- (void)viewDidLoad
{
[super viewDidLoad];
loginViewController *viewController = [[loginViewController alloc] init];
[self.navigationController pushViewController:viewController animated:YES];
}
I am not getting any errors but it's not working.
It just loads the navigation controller with the top nav back button but the rest of the screen is black. It's like it's not loading any view controller.
I am trying to figure out what I am doing wrong.
Any help with this would be great.
Thanks
First add loginViewController class in storyboard and and connect ViewController class to loginViewController class and give identifier name as "identifier_Name".
- (void)viewDidLoad
{
[super viewDidLoad];
[self performSegueWithIdentifier:#"identifier_Name" sender:nil];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"identifier_Name"])
{
loginViewController *viewController = [segue destinationViewController];
}
}
If you're using storyboard, create your login view in the storyboard, link your rootVC to the loginVC with a segue, choose an identifier (for example: "goToLogin"). and then to go in the login view, and use:
[self performSegueWithIdentifier:#"goToLogin" sender:self];
When the user pressed an 'add' button a modal view pops up for them to enter information. I have a 'cancel' button in the top left of a navigation bar and I want it to dismiss the current view controller when it is pressed. How do I set an object as the class's delegate? I understand creating protocols and implementing its methods but I cannot seem to make the delegate be set. When running the debugger my [self delegate] in the 'add' view controller is always nil.
Are you spawning the modal viewController through a segue set up in your Storyboard? If so, then in the prepareForSegue: method you would set the delegate there.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([identifier isEqualToString:#"userGuideSegue_home"]){
UserGuideViewController* vc = segue.destinationViewController;
[[segue destinationViewController] setDelegate:self];
}
}
On the other hand, if you are setting up the modal viewController entirely through code, then you would create an instance of the modal viewController then set it's delegate.
- (void)showModelView:(NSString*)viewName
{
// code ripped out of project so a bit specific
if ([viewName isEqualToString:#"userGuide_name"]) {
modalViewController = (UserGuideViewController * )
[[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:NULL]
instantiateViewControllerWithIdentifier:#"UserGuide"];
}
modalViewController.delegate = self;
modalViewController.modalPresentationStyle = UIModalPresentationFormSheet;
modalViewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
modalViewController.view.frame = [[UIScreen mainScreen] applicationFrame];;
[self presentViewController:modalViewController
animated:YES
completion:^{
//put your code here
}];
}
Of course all this assumes you have defined a delegate property on your modal viewController.
If you created the view in IB, Control-drag the button into the ViewController's header file and add an IBOutlet. Inside of that method in the .m file you can
[self dismissModalViewControllerAnimated:YES];
alternatively you can create the button programmatically:
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(processCancel:)];
-(void)processCancel:(UIBarButtonItem *)item{
[self dismissModalViewControllerAnimated:YES];
}
#interface MyViewController : UIViewController {
id delegate;
}
#property (nonatomic,retain) id delegate;
#synthesize delegate;
This should do the job, you can now use [MyViewController setDelegate:self] before showing the modal view and call [[self delegate] dismissModalViewControllerAnimated:YES] in the cancel button tapped event in MyViewController