TabBatController with viewControllers - viewcontroller

In my tabBarController-based app, I have four tabs - tabA, tabB, tabC and tabD. The user will be able to jump between the tabs.
Now to my question:
- tabA, tabB and tabD have single viewControllers
- tabC though has 3 viewControllers - vc1, vc2 and vc3
I am running into issue where the app remembers which viewController the user was in last, and when the user taps tabC, the control goes to the last view controller that the user was in. For example, let's say the following is the sequence:
User taps tabA : view controller for tabA is shown
User taps tabD : view controller for tabD is shown
User taps tabC : view controller vc1 is shown. On tapping some action, the user is taken to vc3
User taps tabB : view controller for tabB is shown
User taps tabC : the vc3 is shown - instead I'd like to show vc1
So far, I have tried the following in vc1 of tabC, but the control does not come to vc1 at all:
- (void) viewWillAppear:(BOOL)animated {
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:0] animated:YES];
}
How can I tell tabC to always load vc1?
Regards - thanks in advance....
Sam.

Your call to vc1 of tabC likely isn't getting called - viewWillAppear: only gets called when the view will appear on the display.
You might want to look at this function:
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
(Link to Apple Developer docs)
and this function:
- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated
(Link to Apple Developer docs)
If you implement this in your tabBarController delegate, you can act when the user selects tabC, ie:
- (void)tabBarController:(UITabBarController *)tabBarController
didSelectViewController:(UIViewController *)viewController
{
if (viewController == \* tabC view controller */) {
[tabCViewController.navigationController popToRootViewController:YES];
}
}

#dvorak: Thanks for the answer - and sorry to drag on....
I know what I am writing is not an answer - but wanted to show the code that I am working with.
I am not having luck w/ the suggestion. I made the AppDelegate the TabBarControllerDelegate. The callback function gets called - however, using the following code, I am not able to popToRootViewController:
- (void)tabBarController:(UITabBarController *)tbController didSelectViewController:(UIViewController *)viewController {
NSLog(#"ViewController is <%#>", viewController.tabBarItem.title);
if ([viewController.tabBarItem.title isEqualToString:#"tabC"]) {
NSArray *tmp = [viewController.navigationController.tabBarController viewControllers];
[viewController.navigationController popToRootViewControllerAnimated:YES];
}
}
I collected the all ViewControllers in tmp variable , in a hope to see 3 ViewControllers in the array, after visiting all three VCs of tabC. From tabC->vc3, I hit the tabB, and then hit tabC for my exercise. The tmp array had zero elements in the debugger.

Related

resetting to first view controller when tabbaritem is selected

I have a tab bar with 3 items. Each points to a UINavigationController. Each UINavigationController has several viewControllers beneath. I'm wanting to reset back to the first controller in the navigation when any tab bar item is pressed.
I've specified my TabBarController implementation as a delegate
self.delegate = self and my method below (running in my TabBarController implementation works returning UINavigationControllers.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"%#", viewController);
}
With the log file showing e.g.
UINavigationController: 0x8a31a90>2012-12-31 02:16:40.035 Demo[6142:c07]
when I try popToRootViewController or popViewController within this method it doesn't seem to work. I don't get any errors but my viewControllers don't reset. It seems like I've made a really basic error here but I can't tell what.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"%#", viewController);
[self.navigationController popToRootViewControllerAnimated:YES];
[[self navigationController] popViewControllerAnimated:YES];
}
You need to popToRootViewController on the navigationController (viewcontroller) - not the TabViewController (self).
[viewController popToRootViewControllerAnimated:YES];
I'm not sure if this will help. I had a lot of trouble getting this to work and found that I needed to do the following:
In root view controller (first view app comes to), add a delegate in the .h file.
#interface MGMProductsViewController : UIViewController <UITabBarControllerDelegate>
Add the below code to viewDidLoad in root view controller (.m file).
[self.tabBarController setDelegate:self];
Override method in root view controller (.m file) with the below.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
if ([viewController isKindOfClass:[UINavigationController class]])
{
[(UINavigationController*)viewController popToRootViewControllerAnimated:NO];
}
}
I can't attribute this to anyone as I couldn't find the appropriate code again. I think I pieced it together from a few places though the '[self.tabBarController setDelegate:self]' looked to be the key to it working for me.
Good luck.

iOS - is it possible to select view for a uitabbar at runtime?

I am assigning my view controller to my tab right after I create it. Is it possible to select the view that will show after the tab is clicked?
For eg
//user clicks tab 1
if(hasMessages)
//show view A
else
//show view B
Yes, it is possible. You need to set a delegate for your tab controller:
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
tabBarController.delegate = self; // or whatever suitable class you have
This delegate needs to conform to the UITabBarControllerDelegate protocol.
In your delegate, implement tabBarController:didSelectViewController: and inside it, find out which view you want to present. Assuming your tab's root view controller is a navigation controller, then the delegate method implementation would be something like this:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
/* logic goes here */
[viewController pushViewController:someNewVC animated:YES];
}

Displaying an UIViewController that is not present in UITabBarController's controller list

Let me give an example what about what I want to do:
I have a tab that has 4 TabBarItems, so it contains 4 controllers. And there is a controller that must not get shown up in tab bar's icons, but it will get shown when a button inside one of these 4 controllers are touched. So when it get's shown, the tabbar must not have any selected tabs, every item must be deselected. It must be like a ghost controller that is not shown in tab icons but it's actually a controller that's in tab bar controller.
What's the best way to achieve this? Fyi, I don't want a modal dialog, the tabbar must always be visible underneath.
One thing which might help is knowing when a transition between tabs is happening. If you display your ghost view as soon as the transition happens, you might have enough control to do what you want.
Here's how I do that: first, sub-class UITabBarController to TabViewController (for example). In your TabViewController, include this method:
// Pass this message on to views so they know when transitions are occuring
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
UIViewController <UITabBarControllerDelegate> *obj;
for ( obj in self.viewControllers ) {
if ( [obj respondsToSelector:_cmd] ) {
[obj tabBarController:tabBarController didSelectViewController:viewController];
}
}
}
Set each of your tabbed view classes to adopt the UITabBarControllerDelegate protocol. Then, include a method like this in each class to "intercept" the transition events:
// This is called when a transition between tabs happens
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
if ( [viewController isEqual:self] ) {
// Transitioning to me
// Do stuff
}
else {
// Transitioning to someone else
// Do stuff
}
}
(note: there might be cleaner ways of implementing this, but it's been working fine for me...)

Return to first view in UITabBarItem

When I receive a Push Notification, I want to jump to the middle tab on the tabbar and reset the tab (it has multiple table views that the user may have navigated into). I am able to jump to the tab using tabBarController.selectedIndex = 1; ... but how do I reset to the first view?
Implement UITabBarControllerDelegate on a controller class (perhaps your app delegate) and implement tabBarController:didSelectViewController: to pop all pushed view controllers off the navigation stack:
- (void) tabBarController:(UITabBarController *) tabBarController didSelectViewController:(UIViewController *) viewController {
if([viewController isKindOfClass:[UINavigationController class]])
{
[(UINavigationController *)viewController popToRootViewControllerAnimated:YES];
}
}

Disable action - user taps on tabbar item to go to root view controller

I want to disable the default action when user taps the tabbar item.
For example, i have a tabbar with Tab1, Tab2 and Tab3. In Tab1, user can navigate from View1 to View3 (View1 > View2 > View3). If user is at View3, and he taps the Tab1, the application takes the user to View1 (the root view controller). I want to disable this functionality. I don't want the tap on Tab1 to pop all the view controllers. How can i do that?
Edit:
This behavior is a little strange, but a handy shortcut in case of deep hierarchy!
You can implement following UITabBarControllerDelegate methods to disable this system wide shortcut:
#pragma mark -
#pragma mark UITabBarControllerDelegate
- (BOOL)tabBarController:(UITabBarController *)tbc shouldSelectViewController:(UIViewController *)vc {
UIViewController *tbSelectedController = tbc.selectedViewController;
if ([tbSelectedController isEqual:vc]) {
return NO;
}
return YES;
}
if you look at the UITabBarController delegate there is a method:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
If you implement this in your class, you can check if the UIViewController is the already displayed one and then return NO, which will stop this from happening.
I had the same problem with a ABPeoplePicker object embedded in a UITabBarController, in that pressing the 'Contacts' tab a second time which was already displayed would make the ABPeoplePicker control show the 'Groups'