Navigation among tab bar items Programmatically - iphone

I have a Tab bar Controller containing 5 Tabs and each tab bar item has individual navigation controller like :
Now , If i am currently in viewctrller3 of navigationctrller3 in Tab3 and i want to navigate to viewctrller2 of navigationctrller1 in Tab1 programmatically . Also I've selected the particular Tab1 programmatically But i m unable to reach viewctrller2 of
navigationctrller1. Is this feasible ?, If yes , then please elaborate..
Please guys join hands..!

If you are currently in viewctrller3, I think you should be able to do this:
UITabBarController *tabCont = (UITabBarController *)[self.navigationController parentViewController];
[tabCont setSelectedIndex:0];
UINavigationController *nav1 = tabCont.selectedViewController;
NSarray *newControllers = [NSArray arrayWithObjects:[nav1.viewControllers objectAtIndex:2],[nav1.viewControllers objectAtIndex:0],[nav1.viewControllers objectAtIndex:1], nil];
[nav1 setViewcontrollers:newControllers animated:NO];
That last line should rearrange the navigation controller's viewControllers so that viewctrller2 is now the top view controller.

One way to achieve this is
before setting the SelectedIndex of a tabbar , you maintain one reference variable in appDelegate and assign to it the name of the class which is required to be navigated after tab selection.
In the delegate of tabbar controller :
(void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController;
check whether the visible controller is kind of class same as the class name that is set in appdelegate reference variable? If yes then nothing to do , if not then check if that controller is in the navigation stack or not? If its there in stack then pop/push to that index controller else create that controller and push to it.

I dont think that there will be any issue in this. suppose your nav1 is 1st navigationController.
[self.nav1 pushViewController:view2 animated:YES];
its will have to work for you.

From ViewController3 execute..
UINavigationController *navigationController1 = [appDelegate.tabBarController.viewControllers objectAtIndex:2]; // fetch the navigationController
[navigationController1 popToViewController:[navigationController1.viewControllers objectAtIndex:1] animated:NO];
[appDelegate .tabBarController setSelectedIndex:0];

Related

UITabBar MoreViewController image in UITableView disappears after programmatically selecting it

I'm trying to select one of my UINavigationControllers in the UITabBar.viewControllers array.
I previously tried it with setting the UITabbarController.selectedIndex, but the Apple documentation says:
"To select the More navigation controller itself, you must change the value of the selectedViewController property instead."
AppDelegate *appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate;
UINavigationController *navController = [appDelegate.objTabBarController.viewControllers objectAtIndex:5];
[appDelegate.objTabBarController setSelectedViewController:navController];
Doing so is fine but when I change back to the MoreViewController's list view, the icon on the left side is gone and won't come back.
Everything ok, when selecting it with the finger.
Bug when selecting programmatically -> image is gone
Any suggestions what I'm doing wrong?
Best regards,
Steve
Selecting the More Navigation Controller
To select the moreNavigationController, you must set the selectedViewController:
self.tabBarController.selectedViewController = self.tabBarController.moreNavigationController;
The reason for that is simple: The moreNavigationController is not inside the viewControllers of the tab bar controller, so it can't be selected by index.
To select one of the "more" controllers directly, you can either set the selectedViewController property:
self.tabBarController.selectedViewController = viewController5;
Or you can set the selectedIndex:
self.tabBarController.selectedIndex = 5;
Fixing the Disappearing Tab Bar Image
The disappearing tab bar image is caused by using a navigation controller (for the settings) inside a navigation controller (the moreNavigationController generated by the tab bar controller). To fix it, there are two solutions:
Don't add navigation controllers for the more section, but add the controllers directly. The controller structure would look like this, assuming the controllers in all tabs need navigation:
tabBarController
+ navigationController
+ viewController0
+ navigationController
+ viewController1
+ navigationController
+ viewController2
+ navigationController
+ viewController3
+ viewController4
+ viewController5
Set the tabBarItem of the settings controller on its navigation controller (you only need to do this once):
UINavigationController *settingsNavigationController = [appDelegate.objTabBarController objectAtIndex:5];
UIViewController *settingsRootController = settingsNavigationController.viewControllers[0];
settingsNavigationController.tabBarItem = settingsRootController.tabBarItem;
I ran into this same problem. It seems that the navigation controller was somehow losing track of the view controller. In my case, the navigation controller whose image was disappearing was at index 7 in the tabBarController. The navigation controller was supposed to contain a viewController of class SettingsViewController. But sometimes it lost it.
To fix it, I had to add code to two classes -- the app delegate and SettingsViewController. In the app delegate:
-(void) fixSettingsNavigationController {
UITabBarController* tab = self.tabBarController;
NSArray* vcs = tab.viewControllers;
NSInteger nVCs = vcs.count;
if (nVCs > 7) {
UIViewController* settingsContainer = vcs[7];
UINavigationController* settingsContainerNav = (UINavigationController*)settingsContainer;
if ([settingsContainerNav isKindOfClass: [UINavigationController class]]) {
NSArray* settingsNavVCs = settingsContainerNav.viewControllers;
NSInteger count = settingsNavVCs.count;
SettingsViewController* svc = self.settingsViewController;
if (!count) {
// The container navigation controller has lost track of the settings view controller.
settingsContainerNav.viewControllers = [NSArray arrayWithObject:svc];
}
}
}
}
And in SettingsViewController:
-(void) viewWillDisappear:(BOOL)animated {
MyAppDelegate* appDel = [[UIApplication sharedApplication] delegate];
[appDel fixSettingsNavigationController];
[super viewWillDisappear: animated];
}
I ran to the very similar situation, where I want to select a View controller inside MoreViewController programmatically.
As you said in your question, apple don't allow selecting a view controller that is inside MoreViewController (Or not visible in tabbar).
In my case, I don't need default "More" features of reordering tabs in tabbar.
So, I did following things
Created a UITableViewControlelr as my 5th tab, set its Title to more and custom image (Similar to default more image).
In my UITableViewController I listed items that corresponds to ViewControllers. Tapping on which show respective view controller.
When i need to show any view controller that is inside my UITableViewController programatically, i simply set a flag and push my UITableViewController, and in viewDidAppear method of my UITableViewController push desired view controller.
This will also show back button on programatically opened view to list of MoreViewController

popToViewController with a specific UITabBarController Tab/View

I am using popToViewController method to pop to a view controller. What I was trying to achieve is to pop to an UITabBarController's specific index.
NSArray *viewArrays = [self.navigationController viewControllers];
So my view hierarchy is;
<LoginViewController: 0x6b75850>,
<UITabBarController: 0x6ba0b50>,
<RequestViewController: 0x684fe90>,
<ApplyViewController: 0x6845790>
Following code does pops to my UITabBarController, but since I was on the third view of my UITabBarController, it pops back to the third view
[[self navigationController] popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
What I want is to pop to the second view of my UITabBarController.
Edit (Answer)
As stated, we don't push or pop. So in order to gather your tabBarController you either use;
UITabBarController *myTabController = [self.navigationController.viewControllers objectAtIndex:indexOfYourTabBarControllerInYourNavigationController];
myTabController.selectedIndex = indexToGo;
or if you are on one of your tabBarController views;
self.tabBarController.selectedIndex = indexToGo;
In UITabBarController you dont pop and push, if you want to go to the second view you would set the selected index instead
Like so
yourTabController.selectedIndex = 1;
Or if the current view controller is a part of the tabBarController do
self.tabBarController.selectedIndex = 1;

iPad App behavior: a navigationcontroller with a tabbarcontroller with more tabs

For the impatient:
I want to have a navigationcontroller who's root viewcontroller is a tabbarcontroller, similar to the iPad application. I am using IOS 5 and Storyboards.
For the reading inclined:
In my storyboard I have 6 tabs in a UITabBarController that is embeded in a UINavigationController, giving it a "More" button after 3 tabs are shown.
doing so gives me two navigation bars when more is pressed:
So I subclass TabBarController:
//#implentation MyTabController
- (void)viewDidLoad
{
self.moreNavigationController.wantsFullScreenLayout = NO;
self.delegate = self;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
// hide nav bar if current controller is "More" controller
self.navigationController.navigationBarHidden =
viewController == self.moreNavigationController;
}
Great, this gives me:
My guess was that i needed to relayout the views to account for the statusbar, so i try
[self.view setNeedsLayout:YES];
but i get an error saying UIView does not contain a selector for setNeedsLayout so...
How do I get the moreNavigationController.navigationBar to account for the statusbar?
Update:
I have a second related issue with this. When I hit the "Edit" button the edit controller shows modally. Its navigationbar displays underneath the insured controller (after an animation), and does not receive touches.
Pushing a tabBarController into a NavController isn't recommended, instead set a NavigatorController for every tabBar View controller, and set the TabBarController as the main window root view controller.
If you want to be able to show a screen before showing the tabbar, a solution is to push in all the navigator controllers the previous view controller, followed by the one you want to show (that way all navbars has the backbutton). Then set hidesBottomBarWhenPushed = YES to the first view controller, that way it won't show the tabBar.
Example Code:
UIViewController *prevc = [[UIViewController alloc] init];
//prevc.hidesBottomBarWhenPushed = YES;
//Do this for every VC that will be a tabBarItem
UIViewController *vc1 = [[UIViewController alloc] init];
UINavigationController *nv1 = [[UINavigationController alloc] initWithRootViewController:prevc];
[nv1 pushViewController:vc1 animated:NO];
//Remember to set the tabBarItem!
UITabBarController *tb = [[UITabBarController alloc] init];
tb.viewControllers = [NSArray arrayWithObjects:nv1, nv2, nv3, nil];
I just realized that setting hidesBottomBarWhenPushed to the previous ViewController won't work well, but If you show prevc first, and then push the following viewController, you won't have problems. But if anyway you wan't to hide the tab bar while doing a pop, please check this:
hidesBottomBarWhenPushed but when popped
I have also faced a similar problem. In my application also, there is a Tabarcontroller inside a Navigation controller. When i try to switch to a view controller in more navigation controller programatically (like : [self.tabBarController setSelectedIndex:X]; ) the same issues appears in my application. But the following code solves my problem.
self.tabBarController.moreNavigationController.navigationBarHidden = YES;

Why is self.navigationController NULL when pushed from UITabBarController subviews

This is what I am doing. I have a tabBarControllerOne with 5 tabs. On clicking one of the tabs, I present a modal view controller, which has a navigationBar and a TabBarControllerTwo (with 3 tabs). These three tabs are the matter for concern here.
In the 5th Tab of tabBarController I show modalViewController as
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:self.nextTabView];
// navController.navigationBarHidden = YES;
navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
NSLog(#"Displauing the navcontroller before pushing %#", navController);
[self presentModalViewController:navController animated:NO];
Here, nextTabView is a tabBarController with 3 tabs. The views work. In the views, if I try something like.
self.navigationController.navigationBarHidden = YES;
[self.navigationController pushViewController: someController animated:YES];
// nothing works.
If I NSLog, it displays self.navigationController as (null)
Can someone tell me why this is not working ?
Embedding a UITabBarController inside a UINavigationController is not supported. Apple has a careful hierarchy of container view controllers, and a UITabBarController must be the root of its view controller hierarchy.
Additionally, as Joe points out, your views don't belong to the navigation controller; they belong to the tab bar controller, so their navigationController property is not set.
The modal view controller does not belong to a UINavigationController stack therefore the property is not set. You will want to use delegation to notify the creating controller when something is selected then that controller can properly push the next controller on to the stack.
UIViewController Reference:
Discussion
Only returns a navigation controller if the view controller
is in its stack. This property is nil if a navigation controller
cannot be found.

Change ViewController for a TabBarItem

Is it possible to change/replace ViewContoller (and View) for one of the Tabs in a UITabBarController?
I would like to switch between 3 different ViewControllers in any order from a specific Tab (that´s why NavigationController is not possible).
They are set (in mass) using setViewControllers:animated: so you could do something like this.
// Assume tabController is the tab controller
// and newVC is the controller you want to be the new view controller at index 0
NSMutableArray *newControllers = [NSMutableArray arrayWithArray:tabController.viewControllers];
[newControllers replaceObjectAtIndex:0 withObject:newVC];
[tabController setViewControllers:newControllers animated:YES];
Hope that helps.