popToViewController with a specific UITabBarController Tab/View - iphone

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;

Related

Navigation among tab bar items Programmatically

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];

How can I get ViewController from TabBarController on AppDelegate?

I use iOS5 storyboard, and my initial view controller is TabBarController, there are four relationships to view1 & view2 & view3 & view4, so, how can I get the view3's view controller?
I tried:
[[[[self.window.rootViewController navigationController] tabBarController] viewControllers] objectAtIndex:2];
But it doesn't work...
You said that your initial (root) view controller is a UITabBarController but you are referring to a view controller with a navigation controller with a tab bar controller. Are you getting mixed up in your view controller hierarchy?
edit:
if your root view controller is actually just a tab bar controller and you want to get the 3rd tab here is the code:
[[((UITabBarController *)self.window.rootViewController) viewControllers] objectAtIndex:2];
[self.tabBarController setSelectedIndex:2];
Try this way
In any view controller
YourViewController *yourViewController= (YourViewController*) [self.tabBarController.viewControllers objectAtIndex:3];
this return your that view controller object.Cast it to your view controller and you are ready to use that.
run and Go
Swift 4.0
let viewC = self?.tabBarController.viewControllers.first // will give single Navigation Controller on index 0
let viewC = self?.tabBarController?.viewControllers// will give array of Navigation Controller
Further you can check the Visible ViewController
if let nav = viewC as? UINavigationController {
if nav.visibleViewController is YourViewControllerName{
// Do Code
}
}
UIViewController *loginViewController=self.window.rootViewController;
UITabBarController *controller=loginViewController.tabBarControllerObj;
UIViewController *selectedController=controller.selectedViewController;
From this you will get selected view controller.
For getting all view controller just replace
NSArray *viewControllers = [controller viewControllers];

How can I go back to the first view from the third view directly?

When I touch cancel button in the third view, I want to go back to the first view directly. How can I do that?
This is the code.
// this part is in the first view.
SecondController *aSecondController = [[SecondController alloc] init];
UINavigationController *aNaviController = [[UINavigationController alloc] initWithRootViewController:aSecondController];
self.naviController = aNaviController;
[aNaviController release];
[aSecondController release];
[self.view addSubview:naviController.view];
// this part is in the second view.
ThirdController *thirdController = [[ThirdController alloc] initWithStyle:UITableViewStyleGrouped];
[self.navigationController pushViewController:thirdView];
[thirdView release];
// this part is in the third view.
- (void)cancel {
[self.navigationController popViewControllerAnimated:NO]; // this only goes to the second view.
}
popToViewController, popToRootViewController only go to the second view also.
You can use popToRootViewController:animated: method, if your root view controller is the one you're after. You can also use popToViewController:animated: to specify which controller you want to end up with on the top of the navigation stack.
Use UINavigationControllers -popToRootViewControllerAnimated:
- (void)cancel {
[self.navigationController popToRootViewControllerAnimated:NO];
}
And if you ever want to pop to a specific view controller you can use popToViewController:animated: and use the viewControllers property to get the view controller at the correct index.
Set up the navigation controller in your app delegate. Make the first view controller the nav controller's root controller instead of having the first view controller own the nav controller. Then you can use -popToRootViewController:animated: as the other answers have suggested.

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.

How do I pop the view controller underneath a pushed view controller?

I want to push a view controller onto the stack, then pop the first one that pushed the new one.
-(void) someMethod {
MegaSuperAwesomeViewController *tempVC = [[MegaSuperAwesomeViewController alloc] init];
[self.navigationController pushViewController:tempVC animated:YES];
[tempVC release];
// pop this VC, how?
}
EDIT: turns out I can pop back 2 view controllers instead once finished with the new VC. Still not what I wanted exactly, but it works. The downside is I need to set a flag to indicate that the covered view is completed.
Here's a technique of popping back two view controllers, which has a similar problem of yours of the current view controller and its navigationController property going away as soon as you do the first pop:
// pop back 2 controllers on the stack to the setup screen
//
// locally store the navigation controller since
// self.navigationController will be nil once we are popped
//
UINavigationController *navController = self.navigationController;
// retain ourselves so that the controller will still exist once it's popped off
//
[[self retain] autorelease];
// Pop back 2 controllers to the setup screen
//
[navController popViewControllerAnimated:NO];
[navController popViewControllerAnimated:YES];
alternatively, you can directly "party" on the navigation controllers stack of view controllers:
setViewControllers:animated: Replaces
the view controllers currently managed
by the navigation controller with the
specified items.
(void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated Parameters
viewControllers The view controllers
to place in the stack. The
front-to-back order of the controllers
in this array represents the new
bottom-to-top order of the controllers
in the navigation stack. Thus, the
last item added to the array becomes
the top item of the navigation stack.
animated If YES, animate the pushing
or popping of the top view controller.
If NO, replace the view controllers
without any animations. Discussion You
can use this method to update or
replace the current view controller
stack without pushing or popping each
controller explicitly. In addition,
this method lets you update the set of
controllers without animating the
changes, which might be appropriate at
launch time when you want to return
the navigation controller to a
previous state.
If animations are enabled, this method
decides which type of transition to
perform based on whether the last item
in the items array is already in the
navigation stack. If the view
controller is currently in the stack,
but is not the topmost item, this
method uses a pop transition; if it is
the topmost item, no transition is
performed. If the view controller is
not on the stack, this method uses a
push transition. Only one transition
is performed, but when that transition
finishes, the entire contents of the
stack are replaced with the new view
controllers. For example, if
controllers A, B, and C are on the
stack and you set controllers D, A,
and B, this method uses a pop
transition and the resulting stack
contains the controllers D, A, and B.
Availability Available in iOS 3.0 and
later. Declared In
UINavigationController.h
So, to "disappear" the view controller directly under you on the navigation stack, in your view controller's viewDidLoad, you could do this:
NSMutableArray *VCs = [self.navigationController.viewControllers mutableCopy];
[VCs removeObjectAtIndex:[VCs count] - 2];
self.navigationController.viewControllers = VCs;
I had trouble figuring this out also so I wanted to share how I got this to work.
Let's say you have a stack of VCs VC1 being the root then you push VC2 and from VC2 you want to push VC3 but once pushed you don't want the user to go back to VC2 but rather to VC1 (the root). The way to do that is:
//push VC3 from VC2
[[self navigationController] pushViewController:VC3 animated:YES];
// now remove VC2 from the view controllers array so we will jump straight back to VC1
NSMutableArray *viewHeirarchy =[[NSMutableArray alloc] initWithArray:[self.navigationController viewControllers]];
[viewHeirarchy removeObject:self];
self.navigationController.viewControllers = viewHeirarchy;
Hope this helps someone else
Thanks Bogatyr about the tip on 'party on the viewcontroller array for the navcontroller'. I just replaced the entire stack with the one viewcontroller I want to change to, and then log out all the viewcontrollers in the stack to make sure its the only one! Worked great - thanks!
RatingsTableViewController *newViewController = [[RatingsTableViewController alloc] init];
NSMutableArray * newVCarray = [NSMutableArray arrayWithObjects:newViewController, nil];
self.navigationController.viewControllers = newVCarray;
[newViewController release];
NSMutableArray *allControllers = [[NSMutableArray alloc] initWithArray:self.navigationController.viewControllers];
for (id object in allControllers) {
NSLog(#"name VC: %#", object);
}
[allControllers release];
-(void)popToSelf{
NSArray *array = [self.navigationController viewControllers];
for (int i = 0 ; i < array.count ; i++) {
UIViewController *currentVC = [array objectAtIndex:i];
if ([currentVC isKindOfClass:[YourViewControllerClass class]]) {
[self.navigationController popToViewController:[array objectAtIndex:i] animated:YES];
}
}
}