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()

fabdurso
  • 2,366
  • 5
  • 29
  • 55

2 Answers2

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.

Amrit
  • 301
  • 2
  • 14
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

alxlives
  • 5,084
  • 4
  • 28
  • 50