19

I've been trying to find the solution to this for the last week, and I have had no luck after trying every possible solution I could find or think of. Every solution I found and have attempted has either not worked, or been outdated.

I have 5 UITabBarItem's in a UITabBar placed within UITabBarController. I want to change the background color of the UITabBarItem when it is selected, and of course have it change back when the selected item changes.

I am using Swift, and iOS SDK 8.3 in Xcode 6.3.1. If you can only answer in Objective-C that is fine too, any answer will help! Thank you all in advance, I really appreciate it!

EDIT: Here is a visual example of what I would want it to do.

Different Background Color

user2985289
  • 203
  • 1
  • 3
  • 10

5 Answers5

66

In your tabBarController, you can set the default UITabBar tintColor, barTintColor, selectionIndicatorImage (cheating a bit here) and renderingMode of the images, see comments below:

    class MyTabBarController: UITabBarController, UINavigationControllerDelegate {
      ...
      override func viewDidLoad() {
        ...
        // Sets the default color of the icon of the selected UITabBarItem and Title
        UITabBar.appearance().tintColor = UIColor.redColor()

        // Sets the default color of the background of the UITabBar
        UITabBar.appearance().barTintColor = UIColor.blackColor()

        // Sets the background color of the selected UITabBarItem (using and plain colored UIImage with the width = 1/5 of the tabBar (if you have 5 items) and the height of the tabBar)
        UITabBar.appearance().selectionIndicatorImage = UIImage().makeImageWithColorAndSize(UIColor.blueColor(), size: CGSizeMake(tabBar.frame.width/5, tabBar.frame.height))

        // Uses the original colors for your images, so they aren't not rendered as grey automatically.
        for item in self.tabBar.items as! [UITabBarItem] {
          if let image = item.image {
            item.image = image.imageWithRenderingMode(.AlwaysOriginal)
          }
        }
      }
      ...
    }

And you will want to extend the UIImage class to make the plain colored image with the size you need:

extension UIImage {
  func makeImageWithColorAndSize(color: UIColor, size: CGSize) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(size, false, 0)
    color.setFill()
    UIRectFill(CGRectMake(0, 0, size.width, size.height))
    var image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
  }
}
Gwendle
  • 1,951
  • 13
  • 12
  • Very nice answer, thanks. Someone should mark this as correct. In the UIImage extension you are passing a size but you are not using it. I think you meant to write UIRectFill(CGRectMake(0, 0, size.width, size.height)). If I replace this line your solution works perfectly. – Philipp Otto Aug 18 '15 at 15:44
  • This is the only answer that worked for me. Thanks. Only thing I'd change is "UITabBar.appearance().selectionIndicatorImage = UIImage()..." to "UITabBar.appearance().selectionIndicatorImage = UIImage().makeImageWithColorAndSize(UIColor.blueColor(), size: CGSizeMake(tabBar.frame.width/CGFloat(tabBar.items!.count), tabBar.frame.height))" just to make it a bit more plug and play. Thanks again! – jovanjovanovic Oct 30 '15 at 10:37
  • Should be selected as answer – Abdurrahman Feb 08 '16 at 15:11
  • My image isn't stretching out when I use the Iphone 6 simulator. I put the extension but it's still isn't working. – DrPepperGrad Jul 04 '16 at 00:35
  • You will want to divide the the width and height by the screen scale factor in order to get the correct image size for different devices, e.g. `CGSize(width: size.width / UIScreen.main.scale, height: size.height / UIScreen.main.scale)` – Hodson May 31 '17 at 09:38
20

You can try this one. Add this in AppDelegate.swift.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.

        UITabBar.appearance().translucent = false
        UITabBar.appearance().barTintColor = UIColor(rgba: "#12296f")
        UITabBar.appearance().tintColor = UIColor.whiteColor()

        return true
    }

Don't forget to include this library. https://github.com/yeahdongcn/UIColor-Hex-Swift

Nurdin
  • 23,382
  • 43
  • 130
  • 308
4

Inspired by Gwendle, this is how I've solved it:

override func viewWillAppear(animated: Bool) {
    guard let tabBar = tabBarController?.tabBar else { return }
    tabBar.tintColor = UIColor.whiteColor()
    tabBar.selectionIndicatorImage = UIImage().makeImageWithColorAndSize(UIColor.redColor(), size: CGSizeMake(tabBar.frame.width/5, tabBar.frame.height))
    super.viewWillAppear(animated)
}

And also used the extension:

extension UIImage {
    func makeImageWithColorAndSize(color: UIColor, size: CGSize) -> UIImage {
        UIGraphicsBeginImageContext(size)
        color.setFill()
        UIRectFill(CGRectMake(0, 0, size.width, size.height))
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image
}

Keep in mind that after you set the selectionIndicationImage it remains set for all your other tabs. Here's an example how to remove it, by setting it to nil in every other view controller in the remaining tabs:

override func viewWillAppear(animated: Bool) {
    tabBarController?.tabBar.tintColor = UIColor.redColor()
    tabBarController?.tabBar.selectionIndicatorImage = nil
    super.viewWillAppear(animated)
}

Implemented using Swift 2.

Andrej
  • 7,266
  • 4
  • 38
  • 57
0

Have you tried this?

Select the tab bar icon image in your view controller in storyboard.

Look in the Identity and Type (far left) tab (it looks like a piece of paper) on the right panel of xcode.

Look for the global tint setting.

Garret
  • 1,137
  • 9
  • 17
  • Yep, that's it. Are you trying to change the global tint to just your tab bar, or for the entire program? It doesn't work because it's probably overridden at a higher navigation level. – Garret May 04 '15 at 22:58
  • http://stackoverflow.com/questions/22313205/storyboard-global-tint-uitabbar-tint-changed-in-ios-7-1 – Garret May 04 '15 at 22:59
  • Also make sure no lines of code are setting your tint color http://stackoverflow.com/questions/23818808/uibarbuttonitem-title-text-is-always-global-tint-color – Garret May 04 '15 at 23:03
  • Do you have a navigation controller as a part of your storyboard? – Garret May 04 '15 at 23:13
  • In storyboard, click the top part of your tab bar view controller. Then open the attributes inspector. Then play around with the simulated metrics to get what you want. – Garret May 04 '15 at 23:15
  • Yes I do, I have tried it but had no luck :( I updated the original post to include an example image of what i would want it to act like :) [Example](http://imgur.com/bEmUReK) – user2985289 May 04 '15 at 23:20
  • I see, I've never split the tab bar up like that. I'm sorry I can't be of more help. – Garret May 04 '15 at 23:21
0

You can call this function from each controller passing self.tabBarController and each color you want.

Function :

static func customTabBar(controller: UIViewController?, backgroundColor: String, unselectedColor: String, selectedColor: String) {
        if let tabBarController = controller as? UITabBarController {
            tabBarController.tabBar.barTintColor = UIColor(hex: backgroundColor)
            tabBarController.tabBar.tintColor = UIColor(hex: selectedColor)
            tabBarController.tabBar.isTranslucent = false
            tabBarController.tabBar.selectedItem?.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor(hex: selectedColor)], for: UIControl.State.selected)
            if #available(iOS 10.0, *) {
                tabBarController.tabBar.unselectedItemTintColor = UIColor(hex: unselectedColor)
            } else {
                // Fallback on earlier versions
            }
        }
    }
BSK-Team
  • 1,750
  • 1
  • 19
  • 37