0
votes

I am having trouble creating a UINavigationController toolbar programmatically. I have previously used storyboards to do this successfully but would like to try doing it all in code.

I have created the UIBarButtonItems programmatically, but the actual functions or actions they are supposed to perform when pressed are not working.

To clarify, I am NOT attempting to add UIBarButtonItems to the top bar. I've seen dozens of questions all asking the same thing. I am referring to the toolbar at the bottom that comes with the UINavigationController. This means no "rightBarButtonItem" or "leftBarButtonItem"

Here is the code:

class ProgOneViewController: UIViewController {
    var chatRoomsButton: UIBarButtonItem = {
        var button = UIBarButtonItem(title: "Chats", style: .plain, target: self, action: #selector(segueToChatRoomController(_:)))
        return button
    }()

    var exploreButton: UIBarButtonItem = {
        var button = UIBarButtonItem(title: "Explore", style: .plain, target: self, action: #selector(segueToExploreController(_:)))
        return button
    }()

    var profileButton: UIBarButtonItem = {
        var button = UIBarButtonItem(title: "Profile", style: .plain, target: self, action: #selector(segueToProfileController(_:)))

        return button
    }()

    // Flexible spaces that are added in between each button.
    var flexibleSpace1: UIBarButtonItem = {
        var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        return flexibleSpace
    }()

    var flexibleSpace2: UIBarButtonItem = {
        var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        return flexibleSpace
    }()

    var flexibleSpace3: UIBarButtonItem = {
        var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        return flexibleSpace
    }()

    var flexibleSpace4: UIBarButtonItem = {
        var flexibleSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: self, action: nil)
        return flexibleSpace
    }()

    // These are the functions that are not being called for some mysterious reason. 
    func segueToChatRoomController(_ sender: Any) {
        print("segueing to chat rooms controller")
        let chatRoomsController = ChatRoomsViewController()
        let navController = UINavigationController(rootViewController: chatRoomsController)
        self.present(navController, animated: false, completion: nil)
    }

    func segueToExploreController(_ sender: Any) {
        print("segueing to explore controller")
        let exploreController = ExploreCollectionViewController()
        let navController = UINavigationController(rootViewController: exploreController)
        self.present(navController, animated: false, completion: nil)
    }

    func segueToProfileController(_ sender: Any) {
        print("segueing to profile controller")
        let profileController = ProfileTableViewController()
        let navController = UINavigationController(rootViewController: profileController)
        self.present(navController, animated: false, completion: nil)
    }

    func setUpToolbar() {
        print("setting up toolbar")

        self.navigationController?.setToolbarHidden(false, animated: false)
        self.navigationController?.toolbar.isUserInteractionEnabled = true

        let toolBarItems = [flexibleSpace1, chatRoomsButton, flexibleSpace2, exploreButton, flexibleSpace3, profileButton, flexibleSpace4]

        self.setToolbarItems(toolBarItems, animated: true)
        // For some reason, these two methods leave the toolbar empty.

        //self.navigationController?.setToolbarItems(toolBarItems, animated: true)

        //self.navigationController?.toolbar.items = toolBarItems
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = UIColor.white

        setUpToolbar()
    }

 }

EDIT* Here is the code used to instantiate the ProgOneViewController inside a UINavigationController

 func pushToTestProgrammaticallyCreatedViews() {
    let progOneViewController = ProgOneViewController()
    let navController = UINavigationController(rootViewController: progOneViewController)
    //navController.isToolbarHidden = false
    //progOneViewController.setUpToolbar()

    self.present(navController, animated: false, completion: nil)
}

I called this function upon clicking a button in my storyboard-created view controller. The function signature was long in order to specify which viewControllers were tests (created programmatically) :)

1
FYI - you only need one flexible space. It can be used multiple times in the same toolbar. - rmaddy
Thanks for the tip. I assumed otherwise because of the way the view controller subview list usually looks in storyboard. - Chrishon Wyllie

1 Answers

1
votes

first of all you have to make sure that your ProgOneViewController is really included in a UINavigationController. if that is the case the toolbar as well as the barbuttonitems are shown (tried your code in my project).

except of that you have to change all of your barbuttonitem declarations to lazy var so that the references to self within the declarations point to the viewcontroller and target-action works.

feel free to ask if there are any questions :)