173

Let's say I have a UIButton in one tab view in my iPhone app, and I want to have it open a different tab in the tab bar of the TabBarController. How would I write the code to do this?

I'm assuming I unload the existing view and load a specific tab view, but I'm not sure how to write the code exactly.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
rottendevice
  • 2,849
  • 6
  • 30
  • 37
  • I have problems with methods above, guys help in my [question][1] [1]: http://stackoverflow.com/questions/19742416/tabbarcontroller-unload-itself-after-call-modalview – Roman Simenok Nov 02 '13 at 18:54

12 Answers12

427

Try this code in Swift or Objective-C

Swift

self.tabBarController.selectedIndex = 1

Objective-C

[self.tabBarController setSelectedIndex:1];
Jordan
  • 21,746
  • 10
  • 51
  • 63
  • 9
    Note that, if the index maps to a tab within the More view controller (should you have more than five tabs), this will not work. In that case, use `-setSelectedViewController:`. – Joe D'Andrea Mar 02 '12 at 15:43
  • After I do this and it changes tabs successfully, I can no longer select the tab bar normally. UPDATE: this was somehow related to me calling popToRootViewController right before I swapped tabs programmatically. – Adam Johns May 13 '14 at 03:35
  • But how Self wont work if I wanna switch the tab. lets say I click tab 3 and show alertView now as user press ok, I want to switch to tab 1 again. Self wont be right as its not the current object. Correct ? – Alok C Aug 02 '14 at 06:46
  • This works well but I also have to pass the data while switching the tabs. I have got a label in the tab where I switch to that needs to be updated as soon as I switch the tab.! Any easy solution to this? – Md Rais Sep 07 '16 at 12:27
  • @AdamJohns How did you manage to solve your problem. to make it behave like native tabBar. it should pop to rootViewController on second click. – Waqas Oct 18 '19 at 12:12
20

Note that the tabs are indexed starting from 0. So the following code snippet works

tabBarController = [[UITabBarController alloc] init];
.
.
.
tabBarController.selectedViewController = [tabBarController.viewControllers objectAtIndex:4];

goes to the fifth tab in the bar.

John Smith
  • 12,491
  • 18
  • 65
  • 111
13

My opinion is that selectedIndex or using objectAtIndex is not necessarily the best way to switch the tab. If you reorder your tabs, a hard coded index selection might mess with your former app behavior.

If you have the object reference of the view controller you want to switch to, you can do:

tabBarController.selectedViewController = myViewController

Of course you must make sure, that myViewController really is in the list of tabBarController.viewControllers.

ThomasT
  • 131
  • 1
  • 2
9

You can simply just set the selectedIndex property on the UITabBarController to the appropriate index and the view will be changed just like the user tapped the tab button.

Alex Deem
  • 4,717
  • 1
  • 21
  • 24
3

I tried what Disco S2 suggested, it was close but this is what ended up working for me. This was called after completing an action inside another tab.

for (UINavigationController *controller in self.tabBarController.viewControllers)
{
    if ([controller isKindOfClass:[MyViewController class]])
    {
        [self.tabBarController setSelectedViewController:controller];
        break;
    }
}
Joped
  • 1,108
  • 1
  • 11
  • 12
3

Like Stuart Clark's solution but for Swift 3:

func setTab<T>(_ myClass: T.Type) {
    var i: Int = 0
    if let controllers = self.tabBarController?.viewControllers {
        for controller in controllers {
            if let nav = controller as? UINavigationController, nav.topViewController is T {
                break
            }
            i = i+1
        }
    }
    self.tabBarController?.selectedIndex = i
}

Use it like this:

setTab(MyViewController.self)

Please note that my tabController links to viewControllers behind navigationControllers. Without navigationControllers it would look like this:

if let controller is T {
Paintoshi
  • 816
  • 10
  • 12
  • Without looping, no navigation controllers: func selectViewController(type:ViewControllerModel.Type) { self.selectedViewController = self.viewControllers?.first(where: { viewController in viewController is ViewControllerModel }) } – dev_exo Jul 12 '19 at 08:30
3

My issue is a little different, I need to switch from one childViewController in 1st tabBar to home viewController of 2nd tabBar. I simply use the solution provided in the upstairs:

tabBarController.selectedIndex = 2

However when it switched to the home page of 2nd tabBar, the content is invisible. And when I debug, viewDidAppear, viewWillAppear, viewDidLoad, none of them is called. My solutions is to add the following code in the UITabBarController:

override var shouldAutomaticallyForwardAppearanceMethods: Bool 
{
    return true
}
Jin
  • 665
  • 1
  • 7
  • 15
2

For cases where you may be moving the tabs, here is some code.

for ( UINavigationController *controller in self.tabBarController.viewControllers ) {
            if ( [[controller.childViewControllers objectAtIndex:0] isKindOfClass:[MyViewController class]]) {
                [self.tabBarController setSelectedViewController:controller];
                break;
            }
        }
StuStirling
  • 15,601
  • 23
  • 93
  • 150
1

I wanted to be able to specify which tab was shown by class rather than index as I thought it made for a robust solution that was less dependant on how you wire up IB. I didn't find either Disco's or Joped's solutions to work so i created this method:

-(void)setTab:(Class)class{
    int i = 0;
    for (UINavigationController *controller in self.tabBarContontroller.viewControllers){
        if ([controller isKindOfClass:class]){
            break;
        }
        i++;
    }
    self.tabBarContontroller.selectedIndex = i;
}

you call it like this:

[self setTab:[YourClass class]];

Hope this is helpful to someone

Stuart Clark
  • 611
  • 8
  • 13
1
import UIKit

class TabbarViewController: UITabBarController,UITabBarControllerDelegate {

//MARK:- View Life Cycle

override func viewDidLoad() {
    super.viewDidLoad()

}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()

}

//Tabbar delegate method
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
    let yourView = self.viewControllers![self.selectedIndex] as! UINavigationController
    yourView.popToRootViewController(animated:false)
}



}
The iOSDev
  • 5,237
  • 7
  • 41
  • 78
Davender Verma
  • 503
  • 2
  • 12
  • 1
    Usually it's better to explain a solution instead of just posting some rows of anonymous code. You can read [How do I write a good answer](https://stackoverflow.com/help/how-to-answer), and also [Explaining entirely code-based answers](https://meta.stackexchange.com/questions/114762/explaining-entirely-%E2%80%8C%E2%80%8Bcode-based-answers) – Anh Pham Oct 23 '18 at 12:10
  • great! this case if you need to "re-click" on tab, already opened, but covered by another VC – djdance Jan 15 '21 at 14:31
0

Use in AppDelegate.m file:

(void)tabBarController:(UITabBarController *)tabBarController
 didSelectViewController:(UIViewController *)viewController
{

     NSLog(@"Selected index: %d", tabBarController.selectedIndex);

    if (viewController == tabBarController.moreNavigationController)
    {
        tabBarController.moreNavigationController.delegate = self;
    }

    NSUInteger selectedIndex = tabBarController.selectedIndex;

    switch (selectedIndex) {

        case 0:
            NSLog(@"click me %u",self.tabBarController.selectedIndex);
            break;
        case 1:
            NSLog(@"click me again!! %u",self.tabBarController.selectedIndex);
            break;

        default:
            break;

    }

}
Mogsdad
  • 44,709
  • 21
  • 151
  • 275
Rakesh Singh
  • 121
  • 4
0

Like Stuart Clark's solution but for Swift 3 and using restoration identifier to find correct tab:

private func setTabById(id: String) {
  var i: Int = 0
  if let controllers = self.tabBarController?.viewControllers {
    for controller in controllers {
      if let nav = controller as? UINavigationController, nav.topViewController?.restorationIdentifier == id {
        break
      }
      i = i+1
    }
  }
  self.tabBarController?.selectedIndex = i
}

Use it like this ("Humans" and "Robots" must also be set in storyboard for specific viewController and it's Restoration ID, or use Storyboard ID and check "use storyboard ID" as restoration ID):

struct Tabs {
    static let Humans = "Humans"
    static let Robots = "Robots"
}
setTabById(id: Tabs.Robots)

Please note that my tabController links to viewControllers behind navigationControllers. Without navigationControllers it would look like this:

if controller.restorationIdentifier == id {
Paintoshi
  • 816
  • 10
  • 12