Issue Presenting View modally after a UISplitView loads - ipad

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

Related

TabBarController and NavigationController

I am making an application but I'm still a beginner and I'm trying to get used to the RootViewController and how it should be set.
At the beginning my application launches, I want there to be a View which is not in my tabBarController (which is set to be my rootViewController).
What I am trying to ask is, Can I have another view which is outside my UITabBarController launch first without it being in the tabBarController's items list?
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
FacebookFeedViewController *facebookClass = [[FacebookFeedViewController alloc] initWithNibName:#"FacebookFeedViewController" bundle:nil];
TwitterFeedViewController *twitterClass = [[TwitterFeedViewController alloc] initWithNibName:#"TwitterFeedViewController" bundle:nil];
LinkedInFeedViewController *linkClass = [[LinkedInFeedViewController alloc] initWithNibName:#"LinkedInFeedViewController" bundle:nil];
FTLFullFeedViewController *masterClass = [[FTLFullFeedViewController alloc] initWithNibName:#"FTLFullFeedViewController" bundle:nil];
/// tab button title
facebookClass.title = #"Facebook";
twitterClass.title = #"Twitter";
linkClass.title=#"LinkedIn";
masterClass.title=#"FTL";
// tab button Images
facebookClass.tabBarItem.image = [UIImage imageNamed:#"facebook_32"];
twitterClass.tabBarItem.image = [UIImage imageNamed:#"twitter_32"];
WelcomeViewController *welcomeClass= [[WelcomeViewController alloc] initWithNibName:#"WelcomeViewController" bundle:nil];
navController = [[ UINavigationController alloc] initWithRootViewController:welcomeClass];
UINavigationController *navController2 = [[UINavigationController alloc] initWithRootViewController:facebookClass];
UINavigationController *navController3 = [[UINavigationController alloc] initWithRootViewController:twitterClass];
UINavigationController *navController4 = [[UINavigationController alloc] initWithRootViewController:linkClass];
UINavigationController *navController5 = [[UINavigationController alloc] initWithRootViewController:masterClass];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:navController,navController5,navController2,navController3,navController4,nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
I know you already selected an answer but all that's doing is pushing a UITabBar view on top of an existing view, not creating a new UITabBarController view. Based on our brief conversation (latest XCode, no StoryBoards, using XIBs) you're going to want to create a xib as a UITabBarController then push it into view...
View *view = [[View alloc] initWithNibName:#"myUITabBarXIB" bundle:nil];
view.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController: view animated:YES];
This will present your XIB file but not on top of the existing view controller when the desired action takes place.
yes! ofcourse you do.
[self.view addsubview:yourTabbar.view];
Hope this will help you.

Best approach to switch between TabBarController and ViewController

I have been trying an app with initial login screen which then takes to a TabBarController.
I want to know whats the best approach to do this any example code would be appreciated. I have tried it but I am unable to switch from ViewController to TabController.
I'm not sure that this is the best way to do it, but it's quick and dirty and works. Present a modal view controller inside your applicationDidFinishLaunchineWithOptions: method. You should replace the #selector with something more appropriate to what you want to do. Background color is for effect only.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1 = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UIViewController *viewController2 = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
self.tabBarController = [[UITabBarController alloc] init];
self.tabBarController.viewControllers = #[viewController1, viewController2];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
// ***** The relevant code *****
UIViewController *viewController = [[UIViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[[viewController view] setBackgroundColor:[UIColor redColor]];
UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[dismissButton setFrame:CGRectMake(10, 10, 300, 44)];
[dismissButton setTitle:#"Dismiss" forState:UIControlStateNormal];
[dismissButton addTarget:[self tabBarController] action:#selector(dismissModalViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside];
[[viewController view] addSubview:dismissButton];
[[self tabBarController] presentViewController:navigationController animated:NO completion:nil];
return YES;
}
I normally wouldn't like to put this sort of code in the app delegate, but if it's a one-time thing like login details, maybe it's ok.
Assume your root view controller is also your login view.
Now from your root view controller, you can present the tab bar controller a number of ways. One way is to just call the presentViewController method from the root view controller.
Setup
From within the root view controller, sometime before presenting the tab bar, set it up:
myTabBarViewController = [[MyTabBarViewController alloc] init];
[myTabBarViewController setModalPresentationStyle:UIModalPresentationFullScreen];
[myTabBarViewController setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal];
[myTabBarViewController setRootTabBarDelegate:self];
Presentation
When you are ready to present, just call this:
[self presentViewController:myTabBarViewController animated:YES completion:nil];
Notes
The view controller hierarchy looks like this:
AppDelegate
L RootViewController
L MyTabBarController

xcode tabbed application with loginViewController

I am fairly new to xcode so apologies if I am asking bad questions. My issue is that I have created a tabbed application but would like a login screen to show before the tabs display. There a lots of posts about this and the consensus is that you need to get your tabBarController to present a view controller. This makes sense but for some reason my app is not displaying the login screen. I'm going to paste my appDelegate.m code below. Any help would be much appreciated.
Tks
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
sleep(3);
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
LoginViewController *loginViewController = [[[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil] autorelease];
UIViewController *viewController1 = [[[SecondViewController alloc] initWithNibName:#"FirstViewController" bundle:nil] autorelease];
UIViewController *viewController2 = [[[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil] autorelease];
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = #[viewController1, viewController2];
self.window.rootViewController = self.tabBarController;
[loginViewController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[_tabBarController presentViewController:loginViewController animated:YES completion:nil];
[self.window makeKeyAndVisible];
return YES;
}
You should do the presentation from the controller in the first tab (assuming that's the controller you want to show after the login screen is dismissed). Do the presentation from the viewDidAppear method with the animated argument set to NO.

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.

iOS5 SplitViewController leaves BarButton visible while in landscape view on app startup

I have a UISplitViewController with a UIViewController as master and a UINavigationController as my details controller (which contains an actual DetailsController as it's rootController).
In iOS5, at app startup (holding the device in landscape view), I add the splitViewController's view to my window but then I present a loginController on top of the splitViewController like this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
KRMasterViewController *masterViewController = [[[KRMasterViewController alloc] initWithNibName:#"KRMasterViewController" bundle:nil] autorelease];
UINavigationController *masterNavigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];
KRDetailViewController *detailViewController = [[[KRDetailViewController alloc] initWithNibName:#"KRDetailViewController" bundle:nil] autorelease];
UINavigationController *detailNavigationController = [[[UINavigationController alloc] initWithRootViewController:detailViewController] autorelease];
self.splitViewController = [[[UISplitViewController alloc] init] autorelease];
self.splitViewController.delegate = detailViewController;
self.splitViewController.viewControllers = [NSArray arrayWithObjects:masterNavigationController, detailNavigationController, nil];
[self.window addSubview:self.splitViewController.view];
LoginController *controller=[[LoginController alloc]
initWithNibName:#"LoginController" bundle:nil];
[self.splitViewController presentModalViewController:controller animated:false];
[self.window makeKeyAndVisible];
return YES;
}
As you can see the detailsController is my splitViewController's delegate. The problem is in iOS4, before the loginController gets displayed, the delegate method:
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem
forPopoverController:(UIPopoverController *)popoverController
is called then when I dismiss the loginController the delegate method:
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
gets called. I guess iOS realizes really late that I'm in landscape but figures out before I got to the detailController so everything was cool. In iOS 5, the second method does not get called by the time I get to the splitViewController. This means I'm left with the barButtonItem visible in landscape view. Funny enough, if I rotate to portrait then back to landscape, the methods gets called properly from then on. Anyone ever experienced this before? Any solutions?
I've had similar problem. After app launch I present Login modalVC. But when I dismiss it, the BarButtonItem in detailViewController is still visible.
Just use
[self performSelector:#selector(presentLogin) withObject:nil afterDelay:0.1]
and it will magically start working.
I ended up switching the root controller from being a navigation controller (when logging in) to a splitview controller for the main menu:
-(void)goToLogin{
self.rootSplitController=nil;
UINavigationController* navController=[[UINavigationController alloc]init];
navController.navigationBarHidden = true;
self.rootNavController=navController;
[navController release];
LoginController *loginController=[[LoginController alloc]init];
[self.rootNavController pushViewController:loginController animated:false];
[loginController release];
[self.window addSubview:self.rootNavController.view];
}
-(void)goToMain{
self.rootNavController=nil;
MasterController *masterViewController = [[[MasterController alloc]
initWithNibName:#"MasterController" bundle:nil] autorelease];
UINavigationController *masterNavigationController = [[[UINavigationController alloc]
initWithRootViewController:masterViewController] autorelease];
masterNavigationController.navigationBarHidden=true;
DetailsController *detailViewController = [[[DetailsController alloc]
initWithNibName:#"DetailsController" bundle:nil] autorelease];
UINavigationController *detailNavigationController = [[[UINavigationController alloc]
initWithRootViewController:detailViewController] autorelease];
detailNavigationController.navigationBarHidden=true;
self.rootSplitController = [[[UISplitViewController alloc] init] autorelease];
self.rootSplitController.delegate = detailViewController;
self.rootSplitController.viewControllers = [NSArray arrayWithObjects:
masterNavigationController, detailNavigationController, nil];
[self.window addSubview:self.rootSplitController.view];
}

Resources