Talking to A UITabBarController In Story boards - iphone

So In my app, I use a storyboard, and the initial viewController is a UITabBarController. What I want to do is when the app launches, I want to be able to set wheather the tabBarController has 3 items or 4. So in the appDel, I plan to check weather that user should see 3 or 4 tabs, and then the tabBarController should reflect that.
I tried subclassing the tabBarController, but the its not working:
#implementation TabBarController
-(id) init{
if ((self = [super init])) {
[[[[self tabBar] items] objectAtIndex:2] setEnabled:YES];
[[[[self tabBar] items] objectAtIndex:3] setEnabled:NO];
[[[[self tabBar] items] objectAtIndex:3] setHidden:YES];
}
return self;
}
#end
Any help would be apprciated.
Thanks in advance.

I'm thinking the easier (probably not best) way to do this is by having the TabBar controller not be the initial view controller and creating two tab bar controllers. From your initial view you can decide with tab bar controller you will show. You can also have the two tab bar controllers linked to the same tabs/viewcontrollers (the ones that are repeated between them).
In the initial view controller you add some code to know which segue you will perform and voila.
Something like this:
I am looking into a code solution to this though (seems interesting!). Will update if I find anything.
EDIT:
Here's the coded solution. (I am using storyboards but I am sure you can translate the code to work with nib files).
The first thing to do is create an instance of the storyboard:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:[NSBundle mainBundle]];
Then instantiate the tabbarcontroller:
UITabBarController *myTab = [storyboard instantiateViewControllerWithIdentifier:#"tabBar"];
Then instantiate the new view controller you want to add to the tabbar:
UIViewController *newVC = [storyboard instantiateViewControllerWithIdentifier:#"newView"];
This is the interesting part, you put all the view controller/tabs into an array and then add or remove views from that array. Then you set the view controllers of the tabbarcontroller to the modified array (I add one viewController and remove another).
NSMutableArray* controllers = [myTab.viewControllers mutableCopy];
[controllers insertObject:newVC atIndex:0];
[controllers removeObjectAtIndex:2];
[myTab setViewControllers:controllers];
Then you can just push your tab bar controller like this:
[self.navigationController pushViewController:myTab animated:YES];
Here I am using storyboards and ARC, you can modify it for nibs and release the array if you're not using ARC. This was fun to write! hope it helps! cheers!

Related

Subclassing UINavigationController for custom navigation between Views

I am making a small app with the following view hierarchy with UINavigationController:
Login -> Options -> three different views
The problem is that I would like to navigate between the last 3 views in the following manner:
1<->2
1<->3
2<->3
i.e. to be able to switch to any view from any other view, which reminds UITabViewController functionality. So, it is not hierarchical, it is any-to-any graph. To switch between views I will use buttons in the navigation bar.
The easiest way for me is to subclass UINavigationController, add properties that correspond to my views and implement methods for switching between these views (using pushViewController and popToRootViewController). These methods will be called from the views for switching (navigating).
However the reference says that UINavigationController is not intended for subclassing.
http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationController_Class/Reference/Reference.html
What do you recommend me to do?
I'll keep the UINavigationController but instead of using the usual pushViewController:, switch views like this:
NSMutableArray *viewControllers = [self.navigationController.viewControllers mutableCopy];
// from here you can modify the order of controllers as much as you want
[viewControllers addObject:nextViewController];
[viewControllers removeObject:self];
[self.navigationController setViewControllers:viewControllers animated:YES];
If you don't want how the animation turns out, you can set animated:NO and either enclose setViewControllers: in an [UIView animate...] block, or add your own custom CAAnimation to the navigation controller's layer.
Use the below code to add a view controller to a navigation controller,
Navigating From first -> second
SecondViewController *secondView = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
NSMutableArray *navigationarray = [[NSMutableArray alloc] initWithArray:self.navigationController.viewControllers];
[navigationarray removeAllObjects];
[navigationarray addObject:secondView];
self.navigationController.viewControllers = navigationarray;
Navigating From first -> third
ThirdViewController *thirdView = [[ThirdViewController alloc] initWithNibName:#"ThirdViewController" bundle:nil];
NSMutableArray *navigationarray = [[NSMutableArray alloc] initWithArray:self.navigationController.viewControllers];
[navigationarray removeAllObjects];
[navigationarray addObject:thirdView];
self.navigationController.viewControllers = navigationarray;
The above code will removes all the viewControllers from the Navigation Array and places a fresh View Controller
If u want to go to a particular view controller, then use the below code...
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES]
Change the index to ur view controller in the stack.

Can i take tabbar controller in view controller rather than delegate class?

I am using a UINavigation Controller in a delegate class. After navigating the two views class on the third view class I need a tabbar controller which can control three another ViewControllers and the tabbar should not be seen on first two view controllers. How can i do this ?
- (void)viewDidLoad
{
[super viewDidLoad];
self.title =#"Scan";
tabController =[[UITabBarController alloc]init];
ScanTicketView *scan =[[ScanTicketView alloc]initWithNibName:#"ScanTicketView" bundle:nil];
SearchView *search =[[SearchView alloc]initWithNibName:#"SearchView" bundle:nil];
HistoryView *history =[[HistoryView alloc]initWithNibName:#"HistoryView" bundle:nil];
tabController.viewControllers=[NSArray arrayWithObjects:scan,search,history, nil];
[self presentModalViewController:tabController animated:YES];
}
Follow my answer ... you can add and remove tabBar whenEver you want
link
Yes you can. See this link to an example
In your second view controller where you want to push to you third view(tab controller) do this
UITabBarController *tabBarController=[[UITabBarController alloc]init];
tabBarController.viewControllers=[NSArray arrayWithObjects:firstViewController,secondViewController,thirdViewController, nil];
//[self.navigationController pushViewController:tabBarController animated:YES];// this works too but since it seems to be against Apple's Human interface Guidelines you can present the view instead of pushing
[self presentModalViewController:tabBarController animated:NO];
Ideally TabBarcontroller should be the starting case of an app..but in rare cases where you want to present it in a viewcontroller follow ..
UITabBarController *tabBarController=[[UITabBarController alloc]init];
tabBarController.viewControllers=[NSArray arrayWithObjects:firstViewController,secondViewController,thirdViewController, nil];
[self presentModalViewController:tabBarController animated:NO];

How to pop the split view controller "DetailViewController?"

detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController_iPad" bundle:nil];
[self.splitViewController.splitViewController viewWillDisappear:YES];
detailViewController.strDetailId = [teaserSectionOneArray objectAtIndex:indexValue] ;
NSMutableArray *viewControllerArray = [[NSMutableArray alloc] initWithArray:[[self.splitViewController.viewControllers objectAtIndex:1] viewControllers]];
[viewControllerArray removeAllObjects];
[viewControllerArray addObject:detailViewController];
[[self.splitViewController.viewControllers objectAtIndex:1] setViewControllers:viewControllerArray animated:NO];
[self.splitViewController.splitViewController viewWillAppear:YES];
[viewControllerArray release];
This code using for push to the detail view. How do I pop to another view controller in detail view when I click the button? Its not supported the [self.navigationController popViewControllerAnimated:YES];. How to handle this problem? Thanks in advance!
Wooooow thats NOT how you push a view controller on the stack of a navigationController !!
You don't have to call viewWillDisappear, viewWillAppear and such yourself ! You don't have to add the detailViewController to the splitViewController.viewControllers array yourself either!
What you need to do is this:
Make sure your UISplitViewController has a NavigationController as part of its detailViewController (namely the ViewController that is on the right of the screen should be an UINavigationController, not a regular UIViewController).
The rest is then easy as it works the same way as any regular UINavigationController. The fact that your UINavigationController is the right part of an UISplitViewController is not different than when you use an UINavigationController in any other context.
Simply use pushViewController:animated: and popViewControllerAnimated: methods of UINavigationController to push and pop your view controllers. Access your UINavigationController from your UISplitViewController using either a custom IBOutlet that you added to point to it, or by accessing (UINavigationController*)[self.splitViewController.viewControllers objectAtIndex:1].

UINavigationController - basics

I'm trying to use a UINavigationController but I'm uncertain how. Up till now (for about a year), I've been using presentModalViewController and dismissModalViewController to present/dismiss view controllers.
So, this is what I did. My main view controller (the first one that shows on launch) is called MainViewController, and it extends UIViewController.
So I made this launch function in my app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
MainViewController *controller = [[MainViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
And in my MainViewController's viewDidLoad method:
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Title";
self.navigationController.navigationBar.tintColor = [Constants barColor];
....more code...
}
But, in my MainViewController, I'd like to present another view controller called SecondViewController, which needs a UINavigationBar with a back arrow button. So do I make SecondViewController extend UIViewController and do the same thing by setting the title and backButton in the viewDidLoad method? And how do I present it? What should I do to accomplish this?
You'll need to set a root view controller up, it's easiest starting from the apple template.
Here's where the magic happens:
UIViewController *controller = [[UIViewController alloc] initWithNibName:#"MyNib" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
The nav controller does all the work for you (back buttons, titles, animations) - it keeps track!
My workflow is this:
Setup MutableArray in the viewDidLoad, add controllers to it, e.g:
NSMutableArray *array = [[NSMutableArray alloc] init];
MyCustomViewController *customView = [[MyCustomViewController alloc] initWithNibName:#"nib" bundle:#"nil"];
customView.title = #"Second Level";
[array addObject:customView];
self.controllers = array;
Then in your delegate:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = [indexPath row];
UIViewController *childControllerToBe = [controllers objectAtIndex:row];
[self.navigationController pushViewController:childControllerToBe animated:YES];
}
This, along with a lot more can be learnt by reading a decent beginner book such as Beginning iPhone Development
Also, apple docs are always good :)
UINavigationController is a subclass of UIViewController, but unlike UIViewController it’s not usually meant for you to subclass. This is because navigation controller itself is rarely customized beyond the visuals of the nav bar. An instance of UINavigationController can be created either in code or in an XIB file with relative ease.
Please visit "How to add UINavigationController Programmatically"
You should Push it onto the navigation stack.
This Lecture by Stanford's iPhone Course will teach you a lot about Navigation Bars. (It's a quick read)
Basically at the heart of it you need this code:
[self.navigationController pushViewController:SecondView];
You can use PopViewController to go back programmatically, but the Back Button is automatically created.
Here's some source code from the Lecture. It covers exactly what you are having issues with.

Accessing a Top Navigation Controller from a Subview Navigation Controller

I have a my views and controllers set up like so.
A Tab/Bar controller
Within 1. is a root view controller
within 2. is a programmatically created navigation controller, that is displayed as a subview in the root view controller.
What I am trying to do is access the top tab bar/navigation controller so that i can push a view onto it.
I tried parentViewController but all it did was push the view onto the programmed nav controller.
any suggestions?
This is how i set up my root view controller:
-(void)viewDidAppear:(BOOL)animated{
NSLog(#"ROOT APPEARED");
[super viewDidAppear:animated];
WorklistViewController *worklistController = [[WorklistViewController alloc]initWithNibName:#"WorklistView" bundle:[NSBundle mainBundle]];
UINavigationController *worklistNavController = [[UINavigationController alloc] initWithRootViewController:worklistController];
worklistNavController.navigationBar.barStyle = UIBarStyleBlackOpaque;
worklistNavController.view.frame = watchlistView.frame;
[worklistNavController.topViewController viewDidLoad];
[worklistNavController.topViewController viewWillAppear:YES];
[self.view addSubview:worklistNavController.view];
GetAlertRequestViewController *alertsController = [[GetAlertRequestViewController alloc]initWithNibName:#"AlertsView" bundle:[NSBundle mainBundle]];
UINavigationController *alertsNavController = [[UINavigationController alloc] initWithRootViewController:alertsController];
alertsNavController.navigationBar.barStyle = UIBarStyleBlackOpaque;
alertsNavController.view.frame = alertsView.frame;
[alertsNavController.topViewController viewDidLoad];
[alertsNavController.topViewController viewWillAppear:YES];
[self.view addSubview:alertsNavController.view];
}
A nested ViewController (ie, inside a view controlled by a ViewController that's actually on the NavController stack) doesn't have direct access to the UINavigationController that its parent's view's controller is a stack member of. That's one MOUTHFUL of a sentence, but the sense of it is: you can't get there from here.
Instead you've got to get at the app's NavController via the App delegate.
YourAppDelegate *del = (YourAppDelegate *)[UIApplication sharedApplication].delegate;
[del.navigationController pushViewController:nextViewController animated:YES];
You're using your UIApplication's singleton (contains all sorts of good info about your app), which has a .delegate property pointing to the AppDelegate, and that contains a reference to the NavigationController.
This is how the "Navigation-based Application" Xcode template sets up NavController ownership, anyway. YMMV if you rolled your own--though if you did, you probably wouldn't need to ask this question.
You can use the follow instruccion:
[(UINavigationController *)self.view.window.rootViewController pushViewController:vc animated:YES];
It works for me :D
Have a look at UIViewController's navigationController and tabBarController properties. These will return the corresponding navigationController or tabBarController that the given UIViewController 'belongs' to.
So you can do something like:
[customController.navigationController pushViewController:newController animated:YES];
// Similarly for tabBarController ...