Push View from Presented View Controller in iOS - ios

In Short :
How can I PushViewController from Presented ViewController ?
In Brief :
I have MainViewController, In which I have one button on click of button, I am presenting a view called LoginViewController.
On this page (LoginViewController), I again have button, on click of that, I try to push my view controller(called HomeViewController) it doesn't pushes.
Here is my code snippet,
MainViewController.m
- (IBAction)LoginClicked:(id)sender {
LoginViewController *vc = [[LoginViewController alloc] init];
[self presentViewController:vc animated:YES completion:nil];
}
LoginViewController.m
- (IBAction)buttonActionMethodOnLoginView:(id)sender{
NSLog(#"viewControllers %#",APPDELEGATE.nav.viewControllers);
//LoginViewController is not in this array
HomeViewController *obj = [[HomeViewController alloc] init];
[self.navigationController pushViewController:obj animated:YES];
}
But it did not works for me. Also, I printed a stack of view controllers before pushed, but it doesn't have LoginViewController. So, without adding LoginViewController into a stack of view controllers, How can I pushed to HomeViewController from LoginViewController ?
When I getBack from HomeViewController, then LoginViewController should get opened..
Is it possible using doing this single NavigationController?
Note:- Here, I have just taken an example using Login, Home and Main ViewController. But I want that into Other Screens.

hi when you are Presenting you Login view controller Just present a navigationController like:
LoginVC *loginVCObj =[[LoginVC alloc]initWithNibName:#"LoginVC" bundle:nil];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:loginVCObj];
[self presentViewController:nav animated:YES completion:nil];
Now your PresentedViewController is An navigtioncontroller
now you can simply push to your Home VC
HomeViewController *obj = [[HomeViewController alloc] init];
[self.navigationController pushViewController:obj animated:YES];
Hope it will helpful for you

LoginViewController should not be pushed to navigation controller stack. Let me describe below "why".
Our MainViewController should be on the stack - you always want to go back there.
// AppDelegate.m (only if you don't use storyboards, if you do - you don't need to copy this part of code)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// create the window
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setBackgroundColor:[UIColor whiteColor]];
[self.window makeKeyAndVisible];
// set view controllers
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:[[MainViewController alloc] init]];
[self.window setRootViewController:navigationController];
}
On specific action show LoginViewController. You don't want the user to be able to tap back and go to MainViewController. Later, you won't want user to go back to LoginViewController. Because of this, you need to present it as modal:
// inside `MainViewController.m`
- (IBAction)myCoolActionToShowLogin:(id)sender {
[self presentViewController:[[LoginViewController alloc] init] animated:YES completion:nil];
}
Now we can see LoginViewController. When user completes the login, dismiss it and present HomeViewController:
// inside `LoginViewController.m`
- (IBAction)myAwesomeActionToShowHome:(id)sender {
UINavigationController *navigationController = (UINavigationController *)[UIApplication.sharedApplication.keyWindow rootViewController];
[navigationController pushViewController:[[HomeViewController alloc] init] animated:YES];
[self dismissViewControllerAnimated:YES completion:nil];
}
NOTES:
As you may notice, myAwesomeActionToShowHome: expects you have navigation controller as your rootViewController. This is working, but should be nicer - you should check if that navigation is in fact navigation controller instead of casting it. Or you may create a delegate or block to push new one. This is the fastest, easiest working solution, which should be improved later.
You really should read: Apple Developer -> "View Controller Programming" documentation, as these are the core fundamentals you should know to develop & design UX correctly.
Here is the working demo sample.

You can't push from a presented view controller. I suggest, you should maintain your navigation hierarchy.
For that, from your MainViewController, you should present LoginViewController and you should pass navigation controller for the MainViewController.
- (IBAction)openLogin:(id)sender {
LoginViewController *loginVC = (LoginViewController *) [self.storyboard instantiateViewControllerWithIdentifier:#"login"];
[loginVC setReferencedNavigation:self.navigationController];
[self presentViewController:loginVC animated:YES completion:nil];
}
Then inside LoginViewController, you should push to HomeViewController like this,
LoginViewController.h
#interface LoginViewController : UIViewController {
UINavigationController *refNavigationController;
}
- (void) setReferencedNavigation:(UINavigationController *)refNavCon;
LoginViewController.m
- (void) setReferencedNavigation:(UINavigationController *)refNavCon {
refNavigationController = refNavCon;
}
- (IBAction)openHome:(id)sender {
[self dismissViewControllerAnimated:YES completion:^{
UIViewController *homeVC = [self.storyboard instantiateViewControllerWithIdentifier:#"home"];
[refNavigationController pushViewController:homeVC animated:YES];
}];
}
By doing this, it will be look like, you're pushing from LoginViewController but in reality you're pushing from MainViewController.
You can customize this approach to maintain animation and UI for this flow.

1) present a navigation controller with itsroot view controller` set as view controller .
- (IBAction)LoginClicked:(id)sender
{
LoginViewController *loginViewController = [LoginViewController alloc] init];
UINavigationController *navController = [UINavigationController alloc] initWithRootViewController:loginViewController];
[self presentViewController:navController animated:YES completion:nil];
}
- (IBAction)buttonActionMethodOnLoginView:(id)sender
{
HomeViewController *obj = [[HomeViewController alloc] init];
[self.navigationController pushViewController:obj animated:YES];
}
Hope it will work for you.

The problem is that LoginViewController has no navigation controller. Then you give it one.
MainViewController.m
Create a UINavigationController, put LoginViewController in to the stack and present the UINavigationController.
- (IBAction)LoginClicked:(id)sender {
LoginViewController *vc = [[LoginViewController alloc] init];
UINavigationController = nav = [[UINavigationController alloc] init];
nav.viewControllers = #[vc];
[self presentViewController:nav animated:YES completion:nil];
}
LoginViewController.m
- (IBAction)buttonActionMethodOnLoginView:(id)sender{
HomeViewController *obj = [[HomeViewController alloc] init];
[self.navigationController pushViewController:obj animated:YES];
}
Dismiss
Call dismissViewControllerAnimated in your MainViewController.

For Swift 3.0
Present your view controller as a new rootViewController
let navController = UINavigationController.init(rootViewController: self.storyboard!.instantiateViewController(withIdentifier: "SignInViewController"))
self.present(navController, animated: true, completion: {})
Now push your view controller from presented view controller
self.show(self.storyboard!.instantiateViewController(withIdentifier: "SignUpViewController"), sender: self)

Create a UINavigationController instance
[[UINavigationController alloc] initWithRootViewController:[[LoginViewController alloc] init]]
Present that navigationController and then push whatever VC you want to.

MainViewController.m
- (IBAction)LoginClicked:(id)sender {
LoginViewController *vc = [[LoginViewController alloc] init];
UINavigationController *loginNav = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:loginNav animated:YES completion:nil];
}
LoginViewController.m
- (IBAction)buttonActionMethodOnLoginView:(id)sender{
NSLog(#"viewControllers %#",APPDELEGATE.nav.viewControllers);
//LoginViewController is not in this array
HomeViewController *obj = [[HomeViewController alloc] init];
[self.navigationController pushViewController:obj animated:YES];
}

You have to Push from your firstView (MainViewController), but you can use animation same as PresentView and DismissView. Use following code for this :-
For Push (on MainViewController)
LoginViewController *VC = [[LoginViewController alloc]init];
CATransition* transition = [CATransition animation];
transition.duration = 0.3f;
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromTop;
[self.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
[[[UINavigationController alloc] initWithRootViewController:VC] pushViewController:VC animated:NO];
//[self.navigationController pushViewController:VC animated:NO];
For Pop (on LoginViewController)
CATransition* transition = [CATransition animation];
transition.duration = 0.3f;
transition.type = kCATransitionReveal;
transition.subtype = kCATransitionFromBottom;
[self.navigationController.view.layer addAnimation:transition
forKey:kCATransition];
[self.navigationController popViewControllerAnimated:NO];
Using this code, you can get animation same as Present-Dismiss ViewControllers. Refer this answer for more details.
And after that, you can use your code for Pushing LoginViewController to HomeViewController
Hope, this is what you're looking for. Any concern get back to me. :)

This is very simple code for present view controller and push view controller.
- (IBAction)LoginClicked:(id)sender {
LoginViewController *objLogicVC = [LoginViewController alloc] init];
UINavigationController *navPresent = [UINavigationController alloc] initWithRootViewController:objLogicVC];
[self presentViewController:navPresent animated:YES completion:nil];
}
- (IBAction)buttonActionMethodOnLoginView:(id)sender{
HomeViewController *objHomeVC = [[HomeViewController alloc] init];
[self.navigationController pushViewController:objHomeVC animated:YES];
}

simply put this code in objective c on button action
UIViewController *yourViewControllerName = [self.storyboard instantiateViewControllerWithIdentifier:#"yourViewControllerName "];
[[self navigationController] pushViewController:yourViewControllerName animated:YES];

Related

Navigation bar not appearing when pushing a controller from a presented ViewController

I have following code to present a UIViewController (named A) with UINavigationController.
I have kept navigation bar hidden as I do not want it on A by using following code
[self.navigationController.navigationBar setHidden:YES];
but when I push UIViewController named B I want the navigation bar to be displayed but it's not working even If set
self.navigationController?.setNavigationBarHidden(false, animated: false)
on UIViewController B. Can someone help me in this?
Here is the code to present UIViewController A
AppDelegate* delegate = [AppDelegate applicationDelegate];
UIStoryboard *story = [UIStoryboard storyboardWithName:STORYBOARD_MAIN bundle:nil];
SelectionViewController *tutorial = [story instantiateViewControllerWithIdentifier:#"SelectionViewController"];
tutorial.providesPresentationContextTransitionStyle = YES;
tutorial.definesPresentationContext = YES;
[tutorial setModalPresentationStyle:UIModalPresentationOverCurrentContext];
tutorial.delegate = self;
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:tutorial];
navController.modalPresentationStyle = UIModalPresentationFullScreen;
[navController.navigationBar setHidden:YES];
navController.providesPresentationContextTransitionStyle = YES;
navController.definesPresentationContext = YES;
[navController setModalPresentationStyle:UIModalPresentationOverCurrentContext];
[delegate.tabBarController presentViewController:navController animated:YES completion:NULL];
Here is the code to push UIViewController B
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"AppDetail" bundle:nil];
DetailViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"DetailViewController"];
[self.navigationController pushViewController:vc animated:YES];
[[self navigationController] setNavigationBarHidden:NO];
Additional information
UIViewController A is in different storyboard and B is in different
A's code is written in OBJ-C and B's code is in swift.

iOS - some questions about present and push the controllers

There are three controllers here, AViewController, BViewController, CViewController,
the first step: AViewController present to BViewController;
BViewController *BVC = [[BViewController alloc]init];
[self presentViewController:BVC animated:YES completion:nil];
The second step: BViewController push to CViewController;
CViewController *CVC = [[CViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:CVC];
[self.navigationController pushViewController:nav animated:YES];
Now, if I want to go back from CViewController to AViewController, what code should I write?
Just use this code:
self.dismissViewControllerAnimated(true, completion: nil)
to dismiss C ViewController, because C ViewController is now on the Navigation Stack. A present a navigation controller that contain B ViewController. B ViewController push C ViewController, so C is still in Navigation Controller.
You can look at my project here:
https://github.com/khuong291/TestTransition
You should present BViewController like this:
BViewController *BVC = [[BViewController alloc]init];
UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:BVC];
//Setting For Transparent
nav.providesPresentationContextTransitionStyle = YES;
nav.definesPresentationContext = YES;
nav.modalPresentationStyle = UIModalPresentationOverCurrentContext;
[self presentViewController:nav animated:YES completion:nil];
and in BViewController implement:
- (void)viewWillDisappear:(BOOL)animated {
[self.navigationController setNavigationBarHidden:YES];
}
- (void)viewWillDisappear:(BOOL)animated{
[self.navigationController setNavigationBarHidden:NO];
}
And you can push to CViewController:
CViewController *CVC = [[CViewController alloc]init];
[self.navigationController pushViewController:CVC animated:YES];
And when you want back to A. Simple call it in C:
[self dismissViewControllerAnimated:YES completion:nil];

Login Screen and Navigation controller

So in my App.Delegate I'm doing this -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.loginViewController = [[LoginViewController alloc] initWithNibName:#"LoginView" bundle:[NSBundle mainBundle]];
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController: self.loginViewController];
self.window.rootViewController = navigation;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
and in my login controller I'm doing this -
- (IBAction)login:(UIButton *)sender {
NSString *username = self.userName.text;
NSString *password = self.password.text;
[AccountUtils emailLogin:username password:password useCookie:true callback:^(NSDictionary *loginResponseJSON){
if([loginResponseJSON count] != 0){
[self performSelectorOnMainThread:#selector(displaySearchController) withObject:nil waitUntilDone:YES];
// [self performSelectorOnMainThread:#selector(switchState) withObject:nil waitUntilDone:YES];
} else {
//incorrect entry info view here.
}
}];
}
- (void) displaySearchController {
SearchViewController *searchViewController = [[SearchViewController alloc] initWithNibName:#"SearchView" bundle:[NSBundle mainBundle]];
UINavigationController *navigator = self.navigationController;
[navigator popViewControllerAnimated: YES];
[navigator pushViewController: searchViewController animated:YES];
}
If I correctly login, I go to the second controller's view, but at the top I'm still allowed to go 'back' to the login page. I don't want that to happen and I thought this case would be taken care off by the popViewControllerAnimated line. How do I make it so that when I login, I am not allowed to go back to the login page?(in other words, I guess pop the login controller off the navigation controller's stack?)
If you want just to remove the loginVC you could set the new navigationController as the rootViewController of the AppDelegate after the user has logged in. So you could move the displaySearchController method in the AppDelegate and call this method (from the loginVC) after the user has logged in:
-(void)displaySearchController{
SearchViewController *searchViewController = [[SearchViewController alloc] initWithNibName:#"SearchView" bundle:[NSBundle mainBundle]];
UINavigationController *navigation = [[UINavigationController alloc] initWithRootViewController: searchViewController];
self.window.rootViewController=navigation;
}
Otherwise, if you really want the push animation, you can remove the loginVC from the navigationController viewControllers stack in the viewDidAppear of SearchDispalyController:
-(void)viewDidAppear:(BOOL)animated{
NSMutableArray *stackVCs=[self.navigationController.viewControllers mutableCopy];
int idx=[stackVCs indexOfObject:self];
//this remove the previous viewcontroller from the stack
[stackVCs removeObjectAtIndex:idx-1];
self.navigationController.viewControllers=stackVCs;
[super viewDidAppear:animated];
}
Also in the loginVC just before push the searchVC you should call this to hide the back button:
[navigation.navigationItem setHidesBackButton:YES];
You don't want to use a UINavigationController with the LoginViewController and you don't want to push the SearchViewController. Instead, use a UINavigationController with SearchViewController and when you display it, make it the rootViewController.
Do this to achieve what you want.
Move the displaySearchController method to your AppDelegate.m file
Do declare the displaySearchController method in AppDelegate.h file
Now Define the displaySearchController method in AppDelegate.m file as :
- (void) displaySearchController {
SearchViewController *searchViewController = [[SearchViewController alloc] initWithNibName:#"SearchView" bundle:[NSBundle mainBundle]];
UINavigationController *navigator = [[UINavigationController alloc]initWithRootViewController:searchViewController];
self.window.rootViewController = navigator;
}
Call a new local method showNewViewController from your loginController as :
[self performSelectorOnMainThread:#selector(showNewViewController) withObject:nil waitUntilDone:YES];
Now define showNewViewController in your loginController.m file as
-(void)showNewViewController {
AppDelegate *appDele = [UIApplication sharedApplication].delegate;
[appDele displaySearchController];
}
Don't forget to import the AppDelegate.h file to your loginController.m
This will certainly help you.

Switching back and forth in views

very new to obj-c.
I´ve made a simple MainViewController, loading its view from a xib. (From a standard single view template)
On the main view is a button that takes me to another view. Below is the Method:
-(IBAction)forward:(id)sender
{
tvc = [[TrackViewController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]];
[self.view addSubview:tvc.view];
}
On the other view (also loaded from xib) i have a button to take me back to the main view.
Here is my IBAction for returning to the main view:
-(IBAction) back:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
However it does not return to the main view. Not with popToRootViewControllerAnimated: either.
Any response will be appreciated!
This answer applies when you are not using UINavigationBar
In your Forward button you need to write.
TrackViewController *lf = [[TrackViewController alloc]initWithNibName:#"TrackViewController" bundle:nil];
[self presentViewController:TVC animated:YES completion:nil];
and in the Backward screen you should right.
[self dismissViewControllerAnimated:NO completion:nil];
You should load your MainViewController in your AppDelegate in an UINavigationController
MainViewController *mainVC = ...
UINavigationController *naviVC = [[UINavigationController alloc] initWithRootViewController:mainVC];
self.window.rootViewController = naviVC;
Then you can go forward in your MainViewController:
-(IBAction)forward:(id)sender;
{
tvc = [[TrackViewController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:tvc animated:YES];
}
and go back in your other ViewController:
-(IBAction) back:(id)sender {
[self.navigationController popViewControllerAnimated:YES];
}
If your MainViewController is inside a UINavigationController, then the forward method should look like this:
-(IBAction)forward:(id)sender
{
tvc = [[TrackViewController alloc] initWithNibName:nil bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:tvc animated:TRUE];
}

How to make a UIViewController the root of a NavigationController stack?

I'm currently pushing my main UIViewController from appDelegate with this code:
HomeViewController *homeViewController = [[HomeViewController alloc] init];
[self.navigationController pushViewController:homeViewController animated:YES];
//self.navigationController.view = homeViewController.view;
[homeViewController release];
However, I want it to be the root of the UINavigationController controllers stack, while it is currently possible to move back to another root view controller.
Thanks
You can use this method:
- (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated
For example:
HomeViewController *homeViewController = [[HomeViewController alloc] init];
[self.navigationController setViewControllers:[NSArray arrayWithObject:homeViewController] animated:YES];
[homeViewController release];

Resources