Programmatically switching between tabs within Swift
Asked Answered
F

11

95

I need write some code to switch the view to another tab when the iOS app starts (so, for example, the second tab is shown by default rather than the first).

I'm new to Swift, and have worked out the following:

  • The code should probably go in the override func viewDidLoad() function of the ViewController of the first tab.

  • The following code shows the second ViewController, but not with the tab bar at the bottom (vcOptions is the second ViewController tab item:

let vc : AnyObject! = self.storyboard.instantiateViewControllerWithIdentifier("vcOptions")
self.showViewController(vc as UIViewController, sender: vc)

I think the answer may lie in using the UITabbarController.selectedIndex = 1, but not quite sure how to implement this.

Fewell answered 15/8, 2014 at 11:51 Comment(0)
S
165

If your window rootViewController is UITabbarController(which is in most cases) then you can access tabbar in didFinishLaunchingWithOptions in the AppDelegate file.

func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
    // Override point for customization after application launch.

    if let tabBarController = self.window!.rootViewController as? UITabBarController {
        tabBarController.selectedIndex = 1
    }

    return true
}

This will open the tab with the index given (1) in selectedIndex.

If you do this in viewDidLoad of your firstViewController, you need to manage by flag or another way to keep track of the selected tab. The best place to do this in didFinishLaunchingWithOptions of your AppDelegate file or rootViewController custom class viewDidLoad.

Subequatorial answered 15/8, 2014 at 12:10 Comment(4)
Tx for pointing me out! However, I ended up with: if let tababarController = self.window!.rootViewController as! UITabBarController? { tababarController.selectedIndex = tabIndex }Volumetric
can't you do the following in your TabBarViewController: class TabBarViewController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() selectedIndex = 1 } In this case it is just going to select the secondary tab which is what the OP wants to do.Lonnylonslesaunier
Just replace as UITabBarController with as! UITabBarController and it works in Swift 3 too.. Thanks for the answer!Lassitude
in iOS 14.8, the above code can sometimes fail, "Unexpectedly found nil while unwrapping an Optional value", on the self.window! line.Birmingham
S
32

Swift 3

You can add this code to the default view controller (index 0) in your tabBarController:

    override func viewWillAppear(_ animated: Bool) {
        _ = self.tabBarController?.selectedIndex = 1
    }

Upon load, this would automatically move the tab to the second item in the list, but also allow the user to manually go back to that view at any time.

Sabatier answered 27/9, 2016 at 3:17 Comment(2)
Why don't use "tabBarController?.selectedIndex = 1" instead?Socialistic
You should always call super.viewWillAppear(). Also the assignment to _ = is unnecessary.Pleuropneumonia
C
31

1.Create a new class which supers UITabBarController. E.g:

class xxx: UITabBarController {
override func viewDidLoad() {
        super.viewDidLoad()
}

2.Add the following code to the function viewDidLoad():

self.selectedIndex = 1; //set the tab index you want to show here, start from 0

3.Go to storyboard, and set the Custom Class of your Tab Bar Controller to this new class. (MyVotes1 as the example in the pic)

enter image description here

Cycling answered 10/7, 2015 at 7:37 Comment(1)
This worked for me in Xcode 8.2 swift 3. thank you! My app will show the middle (3rd) tab of 5 tabs. class PatientTabBarController: UITabBarController { override func viewDidLoad() { super.viewDidLoad() selectedIndex = 2 } }Saritasarkaria
F
27

The viewController has to be a child of UITabBarControllerDelegate. So you just need to add the following code on SWIFT 3

self.tabBarController?.selectedIndex = 1
Factorial answered 24/5, 2018 at 15:51 Comment(0)
T
21

To expand on @codester's answer, you don't need to check and then assign, you can do it in one step:

func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
    // Override point for customization after application launch.

    if let tabBarController = self.window!.rootViewController as? UITabBarController {
        tabBarController.selectedIndex = 1
    }

    return true
}
Theseus answered 15/8, 2014 at 12:35 Comment(0)
C
15

Swift 5

//MARK:- if you are in UITabBarController 
self.selectedIndex = 1

or

tabBarController?.selectedIndex = 1

if you are using UITabBarController

// UITabBarDelegate
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
    print("Selected item")
    if kAppDelegate.isLoggedIn == false {
        switch tabBar.selectedItem?.title {
        case "Favorite":
            DispatchQueue.main.async {
                self.selectedIndex = 0
                DispatchQueue.main.async {
                    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { timer in
                        self.showAlert(Constants.GlobalConstants.APP_NAME, message: "You are not login.")
                    }
                }
            }
                break
        case "Track Order":
            
            DispatchQueue.main.async {
                self.selectedIndex = 0
                DispatchQueue.main.async {
                    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { timer in
                        self.showAlert(Constants.GlobalConstants.APP_NAME, message: "You are not login.")
                    }
                }
            }
            break
        default:
            break
        }
    }
}
Cyrilcyrill answered 5/3, 2020 at 4:36 Comment(2)
It works for me, but I have a question, why is it necessary to put it in DispatchQueue.main.async?Tanguay
its because your some action call i am not known the sequence so they replace your changes so if we wont use in DispatchQueue its will not work properlyCyrilcyrill
R
5

In a typical application there is a UITabBarController and it embeds 3 or more UIViewController as its tabs. In such a case if you subclassed a UITabBarController as YourTabBarController then you can set the selected index simply by:

selectedIndex = 1 // Displays 2nd tab. The index starts from 0.

In case you are navigating to YourTabBarController from any other view, then in that view controller's prepare(for segue:) method you can do:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
        if segue.identifier == "SegueToYourTabBarController" {
            if let destVC = segue.destination as? YourTabBarController {
                destVC.selectedIndex = 0
            }
        }

I am using this way of setting tab with Xcode 10 and Swift 4.2.

Robb answered 25/9, 2018 at 12:34 Comment(0)
G
4

Try

DispatchQueue.main.async {
   self.tabBarController?.selectedIndex = 1
}
Generic answered 12/10, 2021 at 11:31 Comment(0)
C
2

Just to update, following iOS 13, we now have SceneDelegates. So one might choose to put the desired tab selection in SceneDelegate.swift as follows:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, 
               willConnectTo session: UISceneSession, 
               options connectionOptions: UIScene.ConnectionOptions) {

        guard let _ = (scene as? UIWindowScene) else { return }

        if let tabBarController = self.window!.rootViewController as? UITabBarController {
            tabBarController.selectedIndex = 1
        }

    }
Cutworm answered 24/10, 2019 at 13:16 Comment(0)
M
1

If you want to do this from code that you are writing as part of a particular view controller, like in response to a button press or something, you can do this:

@IBAction func pushSearchButton(_ sender: UIButton?) {
    if let tabBarController = self.navigationController?.tabBarController  {
        tabBarController.selectedIndex = 1
    }
}

And you can also add code to handle tab switching using the UITabBarControllerDelegate methods. Using tags on the base view controllers of each tab, you can see where you are and act accordingly: For example

func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
    
    // if we didn't change tabs, don't do anything
    if tabBarController.selectedViewController?.tabBarItem.tag ==  viewController.tabBarItem.tag {
        return false
    }
    
    if viewController.tabBarItem.tag == 4096 { // some particular tab
        // do stuff appropriate for a transition to this particular tab
    }
    else if viewController.tabBarItem.tag == 2048 { // some other tab
        // do stuff appropriate for a transition to this other tab
    }
}
Manhood answered 9/1, 2021 at 17:53 Comment(1)
@Oliver Spencer please upvote this answer as well.Pattern
S
1

Swift 5

If your class is a subclass of UITabBarController, you can just do:

selectedViewController = viewControllers![yourIndex]
Sociability answered 17/3, 2021 at 16:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.