daydr3am3r
daydr3am3r

Reputation: 954

UIBarButtonItem not showing up as intended

I have a view controller with a segmented control and two container views on it. The UIBarButtonItem is added via storyboard and, initially, it is disabled because selectedSegmentIndex is 0. When the selectedSegmentIndex becomes 1, the button is enabled.

Both container views contain one table view, and tapping on a cell navigates to a different view controller.

When I am in the second container view, which corresponds to selectedSegmentIndex being 1 (and UIBarButtonItem is already visible), and then navigate back, the button remains visible. However, if I am in the first container view, navigate to a different VC and back, and then change the selectedSegmentIndex to 1, the button does not appear.

Not sure if this is clear enough.

I really can't find a way to fix this. Is this the wrong way of hiding / showing a UIBarButtonItem?

@IBOutlet weak var scAdmin: UISegmentedControl!
@IBOutlet weak var btnAdd: UIBarButtonItem!

@IBAction func scAdminAction(_ sender: UISegmentedControl)
{
    print("AdminDashboardVC > scAdminAction")
    
    toggleDisplayedContent(selectedSegmentIndex: sender.selectedSegmentIndex)
}

override func viewWillAppear(_ animated: Bool) 
{
    print("AdminDashboardVC > viewWillAppear")
    
    if (scAdmin.selectedSegmentIndex == 0)
    {
        navigationItem.leftBarButtonItem = nil
    }
    else if (scAdmin.selectedSegmentIndex == 1)
    {
        navigationItem.leftBarButtonItem = btnAdd
    }
}

func toggleDisplayedContent(selectedSegmentIndex: Int)
{
    print("AdminDashboardVC > toggleDisplayedContent > \(selectedSegmentIndex)")
    
    if (selectedSegmentIndex == 0)
    {            
        navigationItem.leftBarButtonItem = nil
    }
    else if (selectedSegmentIndex == 1)
    {            
        navigationItem.leftBarButtonItem = btnAdd
    }
}

Upvotes: 0

Views: 38

Answers (1)

DonMag
DonMag

Reputation: 77672

As a general rule... it is a bad idea to manipulate the view hierarchy of UI elements added in Storyboard / Interface Builder.

You can fix this issue by making btnAdd a strong reference. Change:

@IBOutlet weak var btnAdd: UIBarButtonItem!

to:

@IBOutlet var btnAdd: UIBarButtonItem!

However, I'd suggest you toggle the .isHidden state, rather than removing/re-adding the .leftBarButtonItem:

override func viewWillAppear(_ animated: Bool)
{
    print("AdminDashboardVC > viewWillAppear")
    
    navigationItem.leftBarButtonItem?.isHidden = scAdmin.selectedSegmentIndex == 0
}
@IBAction func scAdminAction(_ sender: UISegmentedControl)
{
    print("AdminDashboardVC > scAdminAction")
    
    toggleDisplayedContent(selectedSegmentIndex: sender.selectedSegmentIndex)
}
func toggleDisplayedContent(selectedSegmentIndex: Int)
{
    print("AdminDashboardVC > toggleDisplayedContent > \(selectedSegmentIndex)")
    
    navigationItem.leftBarButtonItem?.isHidden = selectedSegmentIndex == 0
}

Edit

Since UIBarButtonItem.isHidden is only available for iOS 16+, you can create the btnAdd in viewDidLoad() instead of adding it in Storyboard, and then use your original code:

class YourViewController: UIViewController {

    @IBOutlet weak var scAdmin: UISegmentedControl!
    
    // don't add bar button item in Storyboard
    //@IBOutlet weak var btnAdd: UIBarButtonItem!
    
    var btnAdd: UIBarButtonItem!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // system "+" add button
        btnAdd = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addBtnTapped(_:)))
        
        // or, titled button
        //btnAdd = UIBarButtonItem(title: "Add", style: .plain, target: self, action: #selector(addBtnTapped(_:)))
    }

    // whatever your original button tap func was
    @objc func addBtnTapped(_ sender: Any?) {
        print("add button tapped")
    }


    // the rest of your original code...

}

Upvotes: 0

Related Questions