I'm having troubles hiding the UITabBarController which I defined as my rootViewController for the entire app.
I'm trying to hide the UITabBarController - which is the root view controller for the entire app - on the first view displayed. The idea is that the first view has UIImageView instances which jump to the defined UIViewControllers (which are also defined as view controllers of the root UITabBarController).
Is there a way to have the first view controller without the root UITabBarController but keep it for all other views defined as viewControllers?
Here's the code in AppDelegate defining the view controllers and the UITabBarController as rootViewController.
- (void)initViewControllers {
anIdeaVC = [[IdeaViewController alloc] initWithNibName:#"IdeaViewController" bundle:nil];
[anIdeaVC setTabBarItem:[[[UITabBarItem alloc] initWithTitle:#"Idea" image:[UIImage imageNamed:#"iconIdee.png"] tag:0] autorelease]];
aListTableVC = [[ListTableViewController alloc] initWithStyle:UITableViewStylePlain];
[aListTableVC setTitle:#"List"];
aListNC = [[ListNavigationController alloc] initWithRootViewController:aListTableVC];
[aListNC setTabBarItem:[[[UITabBarItem alloc] initWithTitle:#"List" image:[UIImage imageNamed:#"iconList.png"] tag:0] autorelease]];
anInnMapVC = [[MapViewController alloc] initWithNibName:#"MapViewController" bundle:nil];
anInnMapNC = [[InnMapNavigationController alloc] initWithRootViewController:anInnMapVC];
[anInnMapNC setTabBarItem:[[[UITabBarItem alloc] initWithTitle:#"InnMap" image:[UIImage imageNamed:#"iconInnMap.png"] tag:0] autorelease]];
aSearchTableVC = [[SearchTableViewController alloc] initWithNibName:#"SearchTableViewController" bundle:nil];
[aSearchTableVC setTitle:#"Search"];
aSearchNC = [[SearchNavigationController alloc] initWithRootViewController:aSearchTableVC];
[aSearchNC setTabBarItem:[[[UITabBarItem alloc] initWithTitle:#"Search" image:[UIImage imageNamed:#"iconSearch.png"] tag:0] autorelease]];
tabBarController = [[UITabBarController alloc] init];
[tabBarController setViewControllers:[NSArray arrayWithObjects:anIdeaVC, aListNC, anInnMapNC, aSearchNC, nil] animated:NO];
[tabBarController setSelectedViewController:anIdeaVC];
[tabBarController setDelegate:self];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[self initViewControllers];
[window setRootViewController:tabBarController];
[window makeKeyAndVisible];
return YES;
}
Thanks in advance for your help :-).
I think the best way to go about this is to make the vc with the icons the root to begin with. Then, when user makes a selection, create the tab bar vc and make it the root.
Create a view controller (not just a view) to show the icons and get the user selection. Make that the window's root on launch...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
// don't do this
//[self initViewControllers];
// or this
//[window setRootViewController:tabBarController];
// instead do this, create the vc that lets user select an icon
// put your icon view in there
IconSelectVC *iconSelectVC = [[IconSelectVC alloc] init];
[window setRootViewController:iconSelectVC];
[window makeKeyAndVisible];
return YES;
}
Add the initViewControllers method to your app delegate's public interface, so it can be called from IconSelectVC. Then add one last line to it to make it replace the window's root vc.
// ... the rest of initViewControllers, then
[tabBarController setSelectedViewController:anIdeaVC];
[tabBarController setDelegate:self];
[window setRootViewController:tabBarController];
}
Now, in your IconSelectVC when you decide it's time to change the UI, get the app delegate singleton and change the window's root.
// in IconSelectVC.m
// when you decide to change to the tab bar.
// Be aware that this vc will be released here, so do any cleaning you need to do here
// e.g. unsubscribe from NSNotifications, clean any timers, finish any asynch requests, etc.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate initViewControllers];
EDIT - We didn't discuss how this transition should look - my suggestion here will cause an "ugly" transition (in the eye of the beholder, of course) where the UI just changes in one frame. One way (among a few) to get a nicer transition would be to use os7 custom vc transitions.
Related
I am trying to make a tableview with two views, the tableview controller and the otherView controller. The tableview needs a navigation controller to get to a third view when a cell is clicked. I tried using the code below in my AppDelegate.m but it just creates the tableview with the navigation controller. Any suggestions on how I should edit this to get the tabview working as well? Thanks!
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
AJBTableViewController *masterViewController = [[AJBTableViewController alloc] initWithNibName:nil bundle:nil];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
self.window.rootViewController = self.navigationController;
[self.window makeKeyAndVisible];
_mainTabBar.viewControllers = [NSArray arrayWithObjects:_navigationController, otherViewController, nil];
[_window addSubview:_mainTabBar.view];
return YES;
}
The tab bar controller should be the root view controller of the app, not the navigation controller of the first tab bar item.
_mainTabBar.viewControllers = [NSArray arrayWithObjects:_navigationController, otherViewController, nil];
[_window addSubview:_mainTabBar.view];
Instead this code, you try below code:
UITabBarController *tbC = [[UITabBarController alloc]init];
tbC.viewControllers = [NSArray arrayWithObjects:_navigationController,otherViewController, nil];
self.window.rootViewController = tbC;
and delete
self.window.rootViewController = self.navigationController;
Sorry for the stupid error, I never allocated an instance of the tabbar controller, Mundi is right, making the rootviewcontroller the tabbarcontroller is the way to go.
My requirement is that UITabBarController is the rootviewcontroller and on very first time of app launch I want to show login procedure which is inside UINavCon, and I am displaying it through presentViewController.
I dont want the UITabBarController visible for first time and dont want to how login UINavCon popping as modal.
I want to make user experience that if app starts for first time login UINavCon should be visible. So here is my code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];//is it correct to call it here?
LoginVC *loginObj = [[LoginVC alloc]init];
self.navigationController = [[UINavigationController alloc] initWithRootViewController:cellPhoneNumber];
self.tabBarController = [[UITabBarController alloc]init];
self.window.rootViewController = self.tabBarController;
[self.tabBarController presentViewController:self.navigationController animated:NO completion:^{}];
return YES;
}
I am calling [self.window makeKeyAndVisible]; on second line right after uiwindow alloc init. Is it correct do this or I can experience problems like viewcontroller not receiving events or orientations notifications?
you can call it whenever you want. Calling it affects the window's z-index and screen property.
it doesnt depend on any specific content being set.
You haven't mentioned that whether you got the code working or not by using your implementation. Anyways I have done similar kind of implementation recently where we need to present login controller and then tabBarController after logging in, so just sharing my implementation.
Create your login controller and present it in didFinishLaunching method.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
LoginController *loginCObj= [[[MainScreenController alloc]init]autorelease];
UINavigationController *navigationControllerObj = [[[UINavigationController alloc]initWithRootViewController:loginObj]autorelease];
self.window.rootViewController = navigationControllerObj;
[self.window makeKeyAndVisible];
After that on succesful login in your login view controller, call an appDelegate public method
In login controller
AppDelegate *appDel = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDel applicationLoggedInSuccesfully];
In your appDelegate file, add a method like this:
-(void)applicationLoggedInSuccesfully{
UINavigationController *nv1 = [[[UINavigationController alloc] initWithNibName:nil bundle:nil]autorelease];
TabController1 *v1 = [[[TabController1 alloc] initWithNibName:nil bundle:nil]autorelease];
[nv1 pushViewController:v1 animated:NO];
UITabBarController *tabController = [[[UITabBarController alloc] init]autorelease];
tabController.viewControllers = #[nv1];
tabController.delegate = self;
self.window.rootViewController = tabController;
[self.window makeKeyAndVisible];
}
Hope it will help you.
I am working on a project that uses CoreData one-to-many relationship between folder and files. To show this I am using UISplitViewController, Folders are shown on MasterView and on click of each folder the files are shown on DetailView.Both folders and files are added dynamically.
I have programatically created UISPlitViewController this way
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
FolderViewController = [[FolderViewController alloc] initWithNibName:#"FolderViewController_iPad" bundle:nil];
UINavigationController *masterNavigationController = [[UINavigationController alloc] initWithRootViewController:FolderViewController];
FolderViewController.managedObjectContext = self.managedObjectContext;
fileViewController = [[fileViewController alloc] initWithNibName:#"fileViewController_iPad" bundle:nil];
UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController: fileViewController];
FolderViewController.fileViewController = fileViewController;
self.splitViewController = [[UISplitViewController alloc]init];
self.splitViewController.delegate = fileViewController;
self.splitViewController.viewControllers = #[masterNavigationController, detailNavigationController];
self.window.rootViewController = self.splitViewController;
}
This splits my ipad in to two. Leftside is FolderViewController and rightside is FileViewController.
My master View never hides, in any Orientation.
I have a button on both Master and DetailView which opens common EditViewController modally through splitViewController this way
- (void)Buttonclick
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
testViewController = [[EditViewController alloc] initWithNibName:#"EditViewController" bundle:nil];
m_editViewController.modalPresentationStyle = UIModalPresentationFormSheet;
[appDelegate.splitViewController presentModalViewController:m_editViewController animated:YES];
}
and when I dismiss this View, I add folders or files accordingly.
I dismiss this view this way
[self dismissModalViewControllerAnimated:YES];
I have few doubts here
1) When I launch the app, all imp(main) functions from Both View Controller gets called.is that ok?
2) When I dismiss this ModalView when opened from DetailView, the delegate functions of NSFetchResultsController get called, which are in MasterView . is that ok?
3) As those functions are getting called, my logic fails in some situations.
Regards
Ranjit
I have a tab bar application in Xcode 4.3 and I'm trying to insert a login screen before the tabbar is shown. The app works OK if presentModalViewController has animated:YESbut if it is without animation the view is not showing.
#synthesize window = _window;
#synthesize tabBarController = _tabBarController;
- (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 = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
LogInViewController *logViewController = [[LogInViewController alloc] initWithNibName:#"LogInViewController" bundle:nil];
[self.window addSubview:_tabBarController.view];
[self.tabBarController presentModalViewController:logViewController animated:YES];
//This wont work
//[self.tabBarController presentModalViewController:logViewController animated:NO];
[self.window makeKeyAndVisible];
return YES;
}
-(void)loginDone{
NSLog(#"back to the app delegate");
[self.tabBarController dismissModalViewControllerAnimated:YES];
}
Is this the right way to do it?
Why wont the code work with animated:NO ?
I also get this on output Unbalanced calls to begin/end appearance transitions for <UITabBarController: 0x689d350>.
First of all, move [self.window makeKeyAndVisible]; before your view controller setup.
Additionally, you should be presenting the modal view controller within the viewWillAppear: method of the view controller that will be visible first, to make sure your apps view hierarchy has been fully initialized before presenting your login screen.
Don't do this:
[self.window addSubview:_tabBarController.view];
Do this:
self.window.rootViewController = _tabBarController;
This will put the tabBarController on the screen. But that's not exactly what you want... My advise is:
1) Start by putting the logViewController has the rootViewController as I showed you above.
2) Once you got what you want (login is successful) just tell the AppDelegate to switch the rootViewController. This can be done in with delegation or notifications.
Also, as Toastor indirectly pointed out, you should start the presentViewController from the UIViewController who actually initiates it (and not from the AppDelegate).
I'm experimenting with OAuth 2.0. which brings up a window containing a UIWebView as a canvas for the authentication server to communicate through. Right now, it is being shown as a modal view with its own view controller, and doesn't have a back button or cancel button. So the user has no way to escape from the sign-in process.
I want to have the webView handled by a navigation controller so I can push the webView's view controller.
I am having problems with doing this. It seems to me I should be able to just create a UINavigationController object with the root view controller being the main view controller, like this
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self];
However, this line crashes the program without any error message in the debugger.
I thought I could place a line to push the web view controller immediately after the line above, like this:
[navController pushViewController:windowController animated:YES];
But, without getting past the first line, I can't begin to work out the details on getting the web view to show and then configure the back button.
UPDATE
Here is some context. This is in a single view application. The following code is in the main view controller, which brings up the sign-in dialog. I would like to replace the last line, where the presentModalViewController is called, with a push of the windowController onto a navController stack. Note the commented code at the end, where the initialization of the navigation controller is located.
- (IBAction)signInClicked:(id)sender {
if (![self isSignedIn]) {
// Sign in
[self runSigninThenInvokeSelector:#selector(updateUI)];
}
[self updateUI];
}
- (void)runSigninThenInvokeSelector:(SEL)signInDoneSel {
NSString *clientID = mClientId;
NSString *clientSecret = mClientSecret;
// Show the OAuth 2 sign-in controller
NSString *scope = [GDataServiceGoogleBlogger authorizationScope];
GTMOAuth2ViewControllerTouch *windowController;
windowController = [[GTMOAuth2ViewControllerTouch controllerWithScope:(NSString *)scope
clientID:(NSString *)clientID
clientSecret:(NSString *)clientSecret
keychainItemName:(NSString *)kKeychainItemName
delegate:(id)self
finishedSelector:#selector(windowController:finishedWithAuth:error:)] retain];
//UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self]; // This causes a crash when it is not commented out.
[self presentModalViewController:windowController animated:YES];
}
The application delegate didFinishLaunchingWithOptions is set up this way:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
self.viewController = [[[blogSpotViewController alloc] initWithNibName:#"myNibName" bundle:nil] autorelease];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
}
Well, you can present this as a modal controller. You just need to arrange to call dismissModalViewController: in response to a button or some other event on the 'windowController'.
But if you want to use a navigation controller, then you can set that up in application:didFinishLaunchingWithOptions: like so:
// create window here like now
blogSpotViewController *viewController = [[blogSpotViewController alloc] initWithNibName:#"myNibName" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:viewController];
[viewController release];
// TODO: hold onto this navController in a property if you really need that.
self.window.rootViewController = navController;
[navController release];
// present window here as you are now
This embeds your main view controller in a navigation controller. Then back in your runSigninThenInvokeSelector: you can...
[self.navigationController pushViewController:windowController animated:YES];
Hope that points you in the right direction.