Call NavigationController (xib) from ViewController (storyboard) - ios

I'm normally just use storyboard for my iOS, but needed to integrate an SDK which does not use storyboard, rather xib. My initial view controller is from storyboard, and when a button is pushed (IBAction), I would like it to go to the xib view controller, but not sure how programmatically to do so. Here is my AppDelegate:
//AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:...{
// set to storyboard on launch
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"iPhoneStoryboard"
bundle: nil];
UIViewController* viewController = [mainStoryboard instantiateInitialViewController];
[self.window setRootViewController:viewController];
[window makeKeyAndVisible];
return YES;
}
Here is my code .h:
//mainVC.h
#import <UIKit/UIKit.h>
#interface MainVC : UIViewController{
UIWindow *window;
UINavigationController *navigationController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#property (nonatomic, retain) IBOutlet UIButton *buttonScan;
-(IBAction) ActionScan;
#end
And the .m:
//mainVC.m
#interface MainVC ()
#end
#implementation MainVC
#synthesize window;
#synthesize navigationController;
#synthesize buttonScan;
- (IBAction)ActionScan{
window.rootViewController = navigationController;
[window makeKeyAndVisible];
}

create instance of your xib viewController with initWithNibName
MyViewController *controller = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
& then push this controller instance on navigation controller
[self.navigationController pushViewController:desController animated:YES]

In the view controller in storyboard, code below:
alloc & init destination view controller:
UIViewController *desController = [[SomeViewController alloc]init];
show the destination view controller:
[self.navigationController pushViewController:desController animated:YES]
or
[self.navigationController presentViewController:desController animated:YES completion:nil

Usually you don't set the window's rootViewController directly. Instead you should use
- (IBAction)ActionScan{
[self presentViewController:self.navigationController animated:YES completion:nil];
}
to show your next view controller. The first and accepted answer to this question gives a more detailed explanation of how this works.
Changing root view controller of a iOS Window
Setting window.rootViewController and calling [window makeKeyAndVisible] usually happens in your app delegate, but since you're using storyboards, it is done for you under the hood.
Also, unless you're using multiple windows, you can access your UIWindow from anywhere using your app delegate singleton object.
MyAppDelegateClass *appDelegate = (MyAppDelegateClass*)[[UIApplication sharedApplication] delegate];
UIWindow *mainWindow = appDelegate.window;

Related

Changing root view controller in the background

I have the following view controllers stack.
First, my app will show an app tour page. (Say TourViewController - super class is UIViewController). Added this controller in AppDelegate as rootviewcontroller.
self.window.rootViewController = tourViewController;
Then from the tour page, if the user taps on "Signin" button, I'm presenting the second view controller (Say LoginViewController - super class is UIViewController).
UINavigationController *loginNavigationController = [[UINavigationController alloc] initWithRootViewController:self.loginViewController];
[self presentViewController:loginNavigationController animated:YES completion:nil];
After a successful login, I need to resign the second view controller (LoginViewController) and want to show a tab bar based view for further needs.
I tried this code inside the login success method.
[self dismissViewControllerAnimated:YES completion:^{
TabBarViewController *tabController = [[TabBarViewController alloc] init];
[self presentViewController:tabController animated:NO completion:nil];
AppDelegate *applicationDelegate = [[UIApplication sharedApplication] delegate];
applicationDelegate.window.rootViewController = tabController;
}];
Problems:
When I'm in the LoginViewController, I have two view controllers in my stack. So even I resign the LoginViewController, the another one (TourViewController) remains in the screen.
If I tried the above code, tab bat controller was successfully added as root view controller. But, when the LoginViewController resigns, the background was filled by TourViewController
What I need is, When I resign the LoginViewController, the background view should be tab bar controller instead of TourViewController.
Help needed!!
u can change the root view controller in AppDelegate not in the success method of the loginNavigationController better u can do this way
in AppDelegate.h
#import <UIKit/UIKit.h>
#import "TabControllerViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
- (void)showTabController; //add this method call from on success method of log in completion
#end
in AppDelegate.m
- (void)showTabController;
{
TabControllerViewController *tabController = [[TabControllerViewController alloc] initWithNibName:#"TabControllerViewController" bundle:nil];
self.window.rootViewController = tabController;
[self.window makeKeyAndVisible];
}
and in loginNavigationController.m
[self dismissViewControllerAnimated:YES completion:^{
//TabBarViewController *tabController = [[TabBarViewController alloc] init];
// [self presentViewController:tabController animated:NO completion:nil]; //no nee to present
AppDelegate *applicationDelegate = [[UIApplication sharedApplication] delegate];
[applicationDelegate showTabController]; //there is no need to create a tab bar in loginview controller, create it in root view controller
//applicationDelegate.window.rootViewController = tabController;
}];
NOTE: above is not tested just try it once
Edit 1
one way u can do it but with different animation,
form this answer u can change to second window by doing some animation for example
in in AppDelegate.h
#import <UIKit/UIKit.h>
#import "TabViewController.h"
#import "LoginViewController.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window; //holds initial window, holds tour and login controller
#property (strong, nonatomic) UIWindow *tabWindow; //holds only tab controller
//..other code below is my test
#property (strong, nonatomic) TabViewController *tabViewController;
#property (strong, nonatomic) LoginViewController *loginController;
- (void)showTabController;
#end
in AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_tabWindow = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
_window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
// Override point for customization after application launch.
_loginController = [[LoginViewController alloc]initWithNibName:#"LoginViewController" bundle:nil];
_tabViewController = [[TabViewController alloc] initWithNibName:#"TabViewController" bundle:nil];
self.window.rootViewController = _loginController; //for test for your case it contains tour view controller
[self.window makeKeyAndVisible];
return YES;
}
- (void)showTabController;
{
[UIView transitionWithView:self.window duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
self.window.rootViewController = _tabViewController;
} completion:^(BOOL finished) {
// [_tabWindow makeKeyAndVisible];
}];
}
Do one thing,
Create UINavigationController in AppDelegate.h so you can access it anywhere.
Logic
Whenever you need to change navigation controller you must have to put your Controller to Navigation stack.
So first of all you have to create ViewController/ Tabbarcontroller object and assign it to navigationController and then show the navigationController.
AppDelegate* myDelegate = (((AppDelegate*) [UIApplication sharedApplication].delegate));
InitialViewController *initialVC = [self.storyboard instantiateViewControllerWithIdentifier:#“InitialVC"];
myDelegate.navController = [[UINavigationController alloc] initWithRootViewController:initialVC];
myDelegate.window.rootViewController = myDelegate.navController;
[myDelegate.window makeKeyAndVisible];

navigation controller pushViewController not working

I'm creating an application that has 2 main view controllers at the moment. The app loads into the initial viewController, and clicking a button inside should bring up the second viewController. Here's what I have:
AppDelegate.h
#import <UIKit/UIKit.h>
#import "ViewController1.h"
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) ViewController1 *mainViewCtr;
#property (strong, nonatomic) UINavigationController *navigationController;
#end
AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {
_mainViewCtr = [[ViewController1 alloc] initWithNibName:#"mainViewCtr" bundle:nil];
_navigationController = [[UINavigationController alloc] initWithRootViewController:_mainViewCtr];
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
_window.rootViewController = _navigationController;
_navigationController.delegate = self;
_navigationController.navigationBarHidden = YES;
[_window addSubview:_navigationController.view];
[self.window makeKeyAndVisible];
}
and my button method inside viewcontroller1:
- (IBAction)SessionNickNameSubmit:(id)sender {
ViewController2 *secondViewCtrl = [[ViewController2 alloc] initWithNibName:#"secondViewCtrl" bundle:nil];
[self.navigationController pushViewController:secondViewCtrl animated:YES];
}
but when I click the button the view doesn't change. I tried debugging and the code is hit, but nothing happens.
am I missing a setting somewhere?
UPDATE
I've updated all viewController variable names:
instead of ViewController1/2 I'm using mainViewCtrl and secondViewCtrl
but still no use :(
You made a typo:
it's
_window.rootViewController = _navigationController;
not
_window.rootViewController = _joinViewController;
And NeverHopeless's suggestion is also spot on. It's probably the typo AND the fact that you add your second viewcontroller as ViewController2 and not using a proper variable name.
Another suggestion is making a storyboard (if you are not using one) and adding a segue for the transition. Simply assign the segue processing to the button. Like this:
-(IBAction)SessionNicknameSubmit:(id)sender
{
[self performSegueWithIdentifier:#"identifier" sender:self ];
}
Here is a nice description of how it works and how to use it plus some useful pointers!
Obj-C is a case sensitive language, class name and instance name should not be the same like ViewController2. Try like this:
- (IBAction)SessionNickNameSubmit:(id)sender {
ViewController2 *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[self.navigationController pushViewController:viewController2 animated:YES];
}
The reason is that you have set the window's rootViewController to ViewController1.
You need to set you navigation controller to the window's rootViewController.
So that when you try to access the self.navigationController on the press of the button, it will access the navigation controller in which the self resides i.e. your window's rootViewController now.
Then it will push the next view controller properly.
After looking at almost every tutorial and every stack overflow answer, I finally found a solution that worked. I had to make an instance of the storyboard in the app delegate and use that to create my first view controller instance.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
self.joinViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController1"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:joinViewController];
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
navigationController.navigationBarHidden = YES;
_window.rootViewController = navigationController;
[_window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
I think the problem was that when I was creating an instance of ViewController, it was creating a new instance and binding the navigation controller to it (independent of the view controller that was showing up in the simulator). So when I was using the push method it wasn't recognizing self.NavigationController (that's why NSLog(self.NavigationController == nil) was logging 1

Xib doesn't load as expected

It has been a while since I created a project from scratch. Back then in XCode 4 / 5 the developer was given the choice between storyboard or Xib to get the project started. In Xcode 6 though every template is forced to get started as StoryBoard.
I have removed the story board. Then I have opened info.plist in Supporting files and set Main storyboard file base name : Main to Main storyboard file base name: <blank>.
Then I created a basic testViewController with Xib (same name).
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
#end
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
testViewController *firstViewController = [[testViewController alloc] initWithNibName:nil bundle:nil];
self.navigationController.viewControllers = [NSArray arrayWithObject:firstViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;
}
And this still shows me a black view controller. I checked the xib file, the File owner is set to the view controller and the view delegate is also set.
What am I missing please?
change these two things:
#property (nonatomic, retain) IBOutlet UIWindow *window;
testViewController *firstViewController = [[testViewController alloc] initWithNibName:nil bundle:nil];
To this, and add this code, with the real name or you xib file:
#property (nonatomic, retain) UIWindow *window; // Are you using ARC?
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// I think your xib files is testViewcontroller.xib, if not change it.
testViewController *firstViewController = [[testViewController alloc] initWithNibName:testViewController.xib bundle:nil];
// change this also
self.navigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
return YES;

Set storyboard as starting file instead of xib

Hi i have a xib based project then i have added a storyboard "main.storyboard". But it still running the same xib as initial screen stead of storyboard.
2013-12-18 16:44:14.376 AePubReader[1882:60b] NSMainNibFile and UIMainStoryboardFile are both set. NSMainNibFile ignored.
2013-12-18 16:44:14.396 AePubReader[1882:60b] There is no app delegate set. An app delegate class must be specified to use a main storyboard file.
the following images are make sure that i have given storyboard as starting screen.
my old app delegate for xib file ,now i replace xib uiviewcontroller class from here and put my new storyboard viewcontroller class name
.h file
#import <UIKit/UIKit.h>
#class viewViewController;
#interface AePubReaderAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
viewViewController *detailViewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet viewViewController *detailViewController;
#end
.m file
#import "AePubReaderAppDelegate.h"
#import "ViewController.h"
#implementation AePubReaderAppDelegate
#synthesize window, detailViewController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// // Override point for customization after app launch.
//
// self.window.rootViewController = self.detailViewController;
// [self.window makeKeyAndVisible];
//
// // [detailViewController loadEpub:#"ker"];
return YES;
}
You should open the Info.plist file and delete the "Main nib file base name" key (or keys).
Also make sure that "Main storyboard file name base" key contains the name of your storyboard without extension.
Then fix code in you main.m file. Replace UIApplicationMain call with following line:
UIApplicationMain(argc, argv, nil, NSStringFromClass([AePubReaderAppDelegate class]));
You missed a bit. Try:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"main.storyboard" bundle:nil];
UIViewController *initViewController = [storyBoard instantiateInitialViewController];
[self.window setRootViewController:initViewController];
Under your application didFinishLaunchingWithOptions: in the appdelegate
insert this code:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Your Soryboard name" bundle:nil];
// Instantiate the initial view controller object from the storyboard
initialViewController = [storyboard instantiateInitialViewController];

navigation controller doesn't show up the view

P.S: Please do not suggest me to go with the app delegate way as I will use that in the middle of my app views. Thanx.
I try to use a UINavigationController to display a UITableView like the settings app. So I am trying to start step by step. So far, I try to show up a view contained in a view controller in the navigation stack. But I am missing something somewhere.
Here is my relevant code:
.h file:
#interface ViewController : UINavigationController{
UINavigationController *navigationController;
UIViewController *viewController;
}
#property(nonatomic, strong)IBOutlet UINavigationController *navigationController;
#property(nonatomic, strong)IBOutlet UIViewController *viewController;
#end
.m file :
#implementation ViewController
#synthesize navigationController;
#synthesize viewController;
- (void)viewDidLoad
{
[super viewDidLoad];
//Do any additional setup after loading the view, typically from a nib.
self.viewController = [[UIViewController alloc]init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
[self.navigationController.view addSubview:self.viewController.view];
}
**The xib file:**
When I run the app, I am expecting to see the blue view, but all I see is the default blue navigation bar, without even the "Root View Controller" title message.
If you connect UI from IB, try to delete these line (delete alloc, init)
// self.viewController = [[UIViewController alloc]init];
// self.navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
// [self.navigationController.view addSubview:self.viewController.view];
This link Should help you. You might want to go through this to shed better light on the problem you're having.
https://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/SecondiOSAppTutorial/Introduction/Introduction.html

Resources