8

I have the following TabBarController with 2 items. It is showing correctly.

I'm calling the setupItems() function from another controller when something changes its value.

The function is called correctly, the problem is that the navFirstController.tabBarItem.image is not being updated.

class TabBarController: UITabBarController {

  override func viewDidLoad() {
    super.viewDidLoad()
    setupItems()
  }

  func setupItems() {
    let scale: CGFloat = 0.35
    let navFirstController = UINavigationController(rootViewController: FirstController())

    let navSecondController = UINavigationController(rootViewController: SecondController())
    navSecondController.tabBarItem.image = UIImage.scale(image: UIImage(named: "image2")!, by: scale)
    navSecondController.tabBarItem.imageInsets = UIEdgeInsets(top: 8, left: 0, bottom: -8, right: 0)

    if something == true {
      navFirstController.tabBarItem.image = UIImage.scale(image: UIImage(named: "image1")!, by: scale)
    } else {
      navFirstController.tabBarItem.image = UIImage.scale(image: UIImage(named: "image3")!, by: scale)
    }

    navFirstController.tabBarItem.imageInsets = UIEdgeInsets(top: 8, left: 0, bottom: -8, right: 0)

    viewControllers = [navSecondController, navFirstController]
  }

}

I'ved tried with:

1) viewControllers?.remove(at: 1) at the beginning of setupItems()

2) navFirstController.removeFromParent() at the beginning of setupItems()

3) self.viewWillLayoutSubviews() at the end of setupItems()

4) self.view.setNeedsLayout(), self.view.setNeedsDisplay() at the end of setupItems()

2 Answers 2

1

I don't feel we need to create viewControllers object again just to change tab bar image. Just we need to get viewController object from viewControllers array and change image.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func btnClicked(_ sender: Any) {
        //change image of tab bar item on button clicked
        if let tabVC = self.tabBarController as? TabBarController {
            tabVC.changeImage()
        }
    }

}


class TabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()
        setupItems()
    }

    func setupItems() {
        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
        let firstVC = storyboard.instantiateViewController(withIdentifier: "First")
        let navFirstController = UINavigationController(rootViewController: firstVC)
        navFirstController.tabBarItem.image = UIImage(named: "Image1")

        let secondVC = storyboard.instantiateViewController(withIdentifier: "Second")
        let navSecondController = UINavigationController(rootViewController: secondVC)
        navSecondController.tabBarItem.image = UIImage(named: "Image2")

        viewControllers = [navSecondController, navFirstController]
    }

    func changeImage() {
        if let second = viewControllers?[1] as? UINavigationController {
            second.tabBarItem.selectedImage = UIImage(named: "Image3")
            second.tabBarItem.image = UIImage(named: "Image3")
        }
    }

}

Note if you want to change selected tab bar item image then change "selectedImage" value otherwise change "image" value.

Sign up to request clarification or add additional context in comments.

2 Comments

Can you elaborate more about the issue you are facing in above code.
that the image is not updating.
1

You probably need to set the image's rendering mode to UIImageRenderingModeAlwaysOriginal.

Try changing this:

  navFirstController.tabBarItem.image = UIImage.scale(image: UIImage(named: "image1")!, by: scale)

With this:

  navFirstController.tabBarItem.image = UIImage.scale(image: UIImage(named: "image1")!, by: scale).withRenderingMode(.alwaysOriginal)

EDIT - Sample Code

Consider this setup:

enter image description here

  • The initial view controller is a custom class TabBarViewController
  • The red background view controller is a UIViewController with storyboard ID "First"
  • The orange background view controller is a custom class SecondViewController with an IBAction and storyboard ID "Second"

The Assets.xcassets file has three images (40x40 png):

enter image description here

TabBarViewController

import UIKit

class TabBarViewController: UITabBarController {

    var something: Bool = false

    override func viewDidLoad() {
        super.viewDidLoad()
        setupItems()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }

    func setupItems() {

        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)

        let firstVC = storyboard.instantiateViewController(withIdentifier: "First")
        let navFirstController = UINavigationController(rootViewController: firstVC)
        navFirstController.tabBarItem.image = UIImage(named: "image1")!.withRenderingMode(.alwaysOriginal)

        let secondVC = storyboard.instantiateViewController(withIdentifier: "Second")
        let navSecondController = UINavigationController(rootViewController: secondVC)

        navSecondController.tabBarItem.image = UIImage(named: "image2")!.withRenderingMode(.alwaysOriginal)
        navSecondController.tabBarItem.imageInsets = UIEdgeInsets(top: 8, left: 0, bottom: -8, right: 0)

        if something == true {
            navFirstController.tabBarItem.image = UIImage(named: "image3")!.withRenderingMode(.alwaysOriginal)
        } else {
            navFirstController.tabBarItem.image = UIImage(named: "image1")!.withRenderingMode(.alwaysOriginal)
        }

        navFirstController.tabBarItem.imageInsets = UIEdgeInsets(top: 8, left: 0, bottom: -8, right: 0)

        viewControllers = [navSecondController, navFirstController]
    }

}

SecondViewController

import Foundation
import UIKit

class SecondViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func btnClicked(_ sender: Any) {
        //change image of tab bar item on button clicked
        if let tabVC = self.tabBarController as? TabBarViewController {
            tabVC.something = !tabVC.something
            tabVC.setupItems()
        }
    }

}

OUTPUT

enter image description here

5 Comments

only on image1 or also on image3?
Try changing this behavior on all the images
Can you try without the scale syntax, like this: UIImage(named: "image1")!.withRenderingMode(.alwaysOriginal) ?
I think the problem here is that I don't have to change view controller. The image should change independently of che current view controller.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.