Login Screen and Navigation controller - ios

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.

Related

Push View from Presented View Controller in 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];

Presenting ViewController from appDelegate

I need to show a ViewController from the appDelegate every time the app comes from the background in the applicationDidEnterBackground method.
The *securityCheck prompts the user for a passcode very much like the normal passcode in iOS. Once the passcode is validated I call dimissViewControllerAnimated inside the securityCheck and I am left with my blank UINavigationController, since the view was presented from the appDelegate I have no record of who presented the view, so I can't popToRootViewController.
My question is how can I properly dismiss the SecurityCheckViewController so that it shows the ViewController which the user was on before the app entered the background.
Here's my code:
This method is called inside AppDelegate.m
- (void)securityCheck {
SecurityCheckViewController *securityCheck = [[SecurityCheckViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:securityCheck];
[securityCheck presentedByAppDelegate:YES];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window setRootViewController:navigationController];
[self.window makeKeyAndVisible];
}
Then inside the SecurityCheckViewController.m I have
- (void)unlockWasSuccessfulForPadLockScreenViewController:(ABPadLockScreenViewController *)padLockScreenViewController {
[self.appDelegate securityCheckDone];
[padLockScreenViewController dismissViewControllerAnimated:YES completion:nil];
NSLog(#"Sucsessfull Unlock");I'm
}
Present
- (void)securityCheck {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
SecurityCheckViewController *securityCheck = [storyboard instantiateViewControllerWithIdentifier:#"securityCheckView"];
[self.window.rootViewController presentViewController:securityCheck animated:NO completion:nil];
}
Dismiss
[self dismissViewControllerAnimated:YES completion:nil];
You can call this from application:didFinishLaunchingWithOptions
NOTE: All the storyBoard "initialViewControllers" tick box on the property inspector is turned off
UIStoryboard *storyboard =
[UIStoryboard storyboardWithName:#"Registration" bundle:nil];
RegisterViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"RegisterViewController"];
//this is key else you get a black screen
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
self.window.rootViewController = vc;
[self.window makeKeyAndVisible];

In UINavigationController, button doesn't work with pushViewController

I want to make a simple navigation control application in which I have two view controllers(ViewController and ViewController2). I have a button in ViewController and when I press the button, I want it to go to the other view. The problem is that button doesn't work. I also tried the UIViewController, but didn't work in that way neither.
The AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
ViewController *vc1 = [[ViewController alloc]init];
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController:vc1];
self.window.rootViewController = nav;
[self.window makeKeyAndVisible];
[self.window addSubview:nav.view];
return YES;
}
The ViewController.m
- (IBAction)myButton:(id)sender {
ViewController *vc2 = [[ViewController alloc]init];
[[self navigationController]pushViewController:vc2 animated:YES];
}
Thanks in advance for your help
if you use storyboard import in your ViewController1 the ViewController2 and give a storyboard ID to it "view2":
ViewController2 *vc2 = (ViewController2 *)[self.storyboard instatiateViewControllerWithIdentifier:#"view2"];
[self.navigationController pushViewController:vc2 animated:YES];

iOS selected tab

I'm trying to determine which tab has been selected by the user. I melded this together from a couple of tutorials on iOS tab bars. In my appDelegate I have this code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
//We need to implement the view controllers within the tab controller and make the tab controller the root controller of our app - note we are only using view 1-3 at first.
FirstViewController *fistView = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
ThirdViewController *thirdView = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:nil];
FourthViewController *fourthView = [[FourthViewController alloc] initWithNibName:#"FourthViewController" bundle:nil];
NSArray *viewControllersArray = [[NSArray alloc] initWithObjects:fistView, secondView, thirdView, fourthView, nil];
self.tabController = [[UITabBarController alloc] init];
[self.tabController setViewControllers:viewControllersArray animated:YES];
self.window.rootViewController = self.tabController;
//end custom code
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
Is viewControllerArray the delegate for my tabController?
When I place this code on the page nothing happens:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if (tabBarController.selectedIndex == 0) {
NSLog(#"ok");
}
}
In this case, your app delegate should be the delegate for the tabBarController.
You can simply add self.tabController.delegate = self and make sure that your AppDelegate conforms to the UITabBarControllerDelegate protocol.
I also suggest placing a log outside the if in your delegate method, to confirm that it is actually called.

Issue Presenting View modally after a UISplitView loads

I'm new to UISplitView development, so I'm sure there is something obvious I'm doing wrong. I have a basic UISplitView iPad app that loads up with two UITableView controllers when the app launches. This works just fine.
What I am trying to do is immediately upon launch, presenting an "authentication" view modally so that a user will need to login before continuing. Here is the code I have so far which compiles and works without breaking, but the view is not showing.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
MasterViewController *masterViewController = [[MasterViewController alloc] initWithNibName:#"MasterViewController" bundle:nil];
UINavigationController *masterNavigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:detailViewController];
self.splitViewController = [[UISplitViewController alloc] init];
self.splitViewController.delegate = detailViewController;
self.splitViewController.viewControllers = [NSArray arrayWithObjects:masterNavigationController, detailNavigationController, nil];
masterViewController.detailViewController = detailViewController;
masterViewController.managedObjectContext = self.managedObjectContext;
self.window.rootViewController = self.splitViewController;
[self presentAuthenticate];
[self.window makeKeyAndVisible];
applicationDidLaunch = YES;
return applicationDidLaunch;
}
- (void) presentAuthenticate {
AuthenticateViewController *loginController = [[AuthenticateViewController alloc] initWithNibName:#"AuthenticateViewController" bundle:nil];
[loginController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[loginController setModalPresentationStyle:UIModalPresentationFormSheet];
if ([self.splitViewController respondsToSelector:#selector(presentViewController:animated:completion:)]) {
[self.splitViewController presentViewController:loginController animated:NO completion:nil];
} else {
[self.splitViewController presentModalViewController:loginController animated:NO]; //iOS 4 works fine with or without animation
}
}
I defined the AuthenticateViewController as a View with a few textfields in it and have it wired to the File's Owners view.
Thanks ahead of time!
A viewcontroller will not allow to push/present on anotherview unless and until the view is complete loading.
Simple saying we are not allow to call presentModalViewController/pushViewController in a viewcontroller viewDidLoad/viewWillAppear. we need to call this in viewDidAppear.
I had the same issue you said.
Some Solution I can say are,
Do the loading of AuthenticateViewController after [self.window makeKeyAndVisible]; and in a performSelctor (may be with a delay).
Move the code to display AuthenticateViewController in SplitView's DetailView controller viewDidAppear.
thanks,
Naveen Shan

Resources