62

I have an UITabBar with 5 items. I want to change the unselected color of all items. The items aren't declared in the UIViewController classes (i built them and linked the views in the Storyboard).

Is there an code like this : [[UITabBar appearance] set***UN***SelectedImageTintColor:[UIColor whiteColor]]; ?

logeshpalani98
  • 1,112
  • 9
  • 25
user1530090
  • 635
  • 1
  • 5
  • 6
  • You can check this answare for iOS7: http://stackoverflow.com/questions/15086276/uitabbaritem-image-color-is-grey-while-original-image-is-white/22937172#22937172 – Cornel Damian Apr 08 '14 at 12:37
  • Possible duplicate of [Change tab bar item selected color in a storyboard](http://stackoverflow.com/questions/26835148/change-tab-bar-item-selected-color-in-a-storyboard) – Marcelo Gracietti Jan 01 '17 at 23:55

14 Answers14

98

In iOS 10 and higher, there are 3 possible easy solutions:

A. Instance from code (Swift):

self.tabBar.unselectedItemTintColor = unselectedcolor

B. Instance from IB:

Add a Key Path: unselectedItemTintColor of type: Color

C. Global appearance (Swift):

UITabBar.appearance().unselectedItemTintColor = unselectedcolor

Lukas Würzburger
  • 6,207
  • 7
  • 35
  • 68
vtcajones
  • 1,642
  • 1
  • 12
  • 9
  • 8
    Your answer made me realize that we can also do this with "User Defined Runtime Attributes" by adding the "unselectedItemTintColor" Key Path in the attributes inspector if your using a storyboard. Thank you! – Jeff Nov 08 '16 at 20:14
  • 2
    Doesn't works if you also support lower version (< iOS 10) – Phil Feb 27 '17 at 10:22
96

This will not work under iOS 7 as far as I can say. In particular, tintColor of the tab bar will define the color of the selected tab, not of the unselected ones. If you want to change the default in iOS 7, it seems that you have to actually use different icons (in the color you like to have for unselected tabs) and set the color of the text.

This example should tint selected tabs to red and render others in green. Run this code in your TabBarController:

// set color of selected icons and text to red
self.tabBar.tintColor = [UIColor redColor];
[[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor redColor], NSForegroundColorAttributeName, nil] forState:UIControlStateSelected];


// set color of unselected text to green
[[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor greenColor], NSForegroundColorAttributeName, nil]
                                         forState:UIControlStateNormal];

// set selected and unselected icons
UITabBarItem *item0 = [self.tabBar.items objectAtIndex:0];

// this way, the icon gets rendered as it is (thus, it needs to be green in this example)
item0.image = [[UIImage imageNamed:@"unselected-icon.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];

// this icon is used for selected tab and it will get tinted as defined in self.tabBar.tintColor
item0.selectedImage = [UIImage imageNamed:@"selected-icon.png"];

If you set the icon in the story board only, you can control the color of the selected tab only (tintColor). All other icons and corresponding text will be drawn in gray.

Maybe someone knows an easier way to adopt the colors under iOS 7?

Willow Bumby
  • 43
  • 1
  • 1
  • 5
Sven Tiffe
  • 1,141
  • 1
  • 8
  • 7
71

Extending @Sven Tiffe’s answer for iOS 7, you can get your code to automatically tint the unselected UITabBar images added in the storyboard. The following approach will save you having to create two sets of icon images (i.e. selected vs unselected) and having to programatically load them in. Add the category method imageWithColor: (see - How can I change image tintColor in iOS and WatchKit) to your project then put the following in your custom UITabBarController viewDidLoad method:

// set the selected colors
[self.tabBar setTintColor:[UIColor whiteColor]];
[[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys: [UIColor whiteColor], NSForegroundColorAttributeName, nil] forState:UIControlStateSelected];


UIColor * unselectedColor = [UIColor colorWithRed:184/255.0f green:224/255.0f blue:242/255.0f alpha:1.0f];

// set color of unselected text
[[UITabBarItem appearance] setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:unselectedColor, NSForegroundColorAttributeName, nil]
                                         forState:UIControlStateNormal];

// generate a tinted unselected image based on image passed via the storyboard
for(UITabBarItem *item in self.tabBar.items) {
    // use the UIImage category code for the imageWithColor: method
    item.image = [[item.selectedImage imageWithColor:unselectedColor] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}

Create a Category called UIImage+Overlay and on UIImage+Overlay.m (extracted from this answer ) :

@implementation UIImage(Overlay)

- (UIImage *)imageWithColor:(UIColor *)color1
{
        UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(context, 0, self.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextSetBlendMode(context, kCGBlendModeNormal);
        CGRect rect = CGRectMake(0, 0, self.size.width, self.size.height);
        CGContextClipToMask(context, rect, self.CGImage);
        [color1 setFill];
        CGContextFillRect(context, rect);
        UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return newImage;
}
@end
Community
  • 1
  • 1
Kpalser
  • 733
  • 5
  • 7
  • 1
    This one is by far the easiest way to accomplish the task, not sure why it is not marked as the accepted answer. – user717452 Jul 25 '14 at 18:37
  • 1
    In my case, adding the above code to viewWillAppear did the trick. (The buttons aren't loaded yet at the time viewDidLoad is called in my app, so the above code only changes the text color if it's placed in viewDidLoad). – Arda Feb 13 '15 at 21:57
  • I think it should be `item.image = [[item.image imageWithColor...]]`. Also including the code for `imageWithColor` would improve your answer. – Sebastian Jul 06 '15 at 16:14
  • This worked beautifully. For those (like me) who had never heard of categories before, use this: http://stackoverflow.com/questions/24324021/how-do-i-create-a-category-in-xcode-6 http://rypress.com/tutorials/objective-c/categories – rob123 Jul 31 '15 at 08:48
  • There's a good discussion of tinting existing images, including those with gradients, in the context of theming your app (and this extends to unselected UITabBarItem icons) on the Thoughbot blog here: https://robots.thoughtbot.com/designing-for-ios-blending-modes. It's broadly the same approach as used in this answer. Can confirm it works on iOS8 and ports trivially to Swift. – Robin Macharg Sep 07 '15 at 15:27
  • Spent hours and hours trying to find a solution for this! Excellent and elegant solution. – Dan Winter-Wijntjes Nov 25 '15 at 03:03
  • Just the fact that we have to do this in iOS is beyond me. I shouldn't have to tell iOS to not mess with my images. – Perry Mar 30 '16 at 21:00
26

SO says i cannot delete the accepted answer (i tried), but obviously, there are a lot of upvotes for comments that this doesn't work for iOS 7.

See the other answer below with many more upvotes, or the link in @Liam's comment to this answer.


for iOS 6 only

It should be as simple as this:

[[UITabBar appearance] setTintColor:[UIColor grayColor]]; // for unselected items that are gray
[[UITabBar appearance] setSelectedImageTintColor:[UIColor greenColor]]; // for selected items that are green
john.k.doe
  • 7,474
  • 2
  • 35
  • 63
  • 1
    This does not work in iOS 7. Here's [another solution](http://stackoverflow.com/questions/22767098/how-to-change-inactive-icon-text-color-on-tab-bar) that worked for me. – Liam May 21 '14 at 09:21
  • 12
    For iOS 10 .use this `self.dashboardTabBar.unselectedItemTintColor = UIColor.black` – Anish Parajuli 웃 Dec 01 '16 at 15:48
22

Swift version in iOS 10 and higher -

UITabBar.appearance().tintColor = UIColor.gray
UITabBar.appearance().unselectedItemTintColor = UIColor.gray
Abhishek Jain
  • 4,155
  • 2
  • 27
  • 29
18

Translating user3719695's answer to Swift, which now uses extensions:

UIImage+Overlay.swift

extension UIImage {
  func imageWithColor(color1: UIColor) -> UIImage {
    UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
    color1.setFill()

    let context = UIGraphicsGetCurrentContext()
    CGContextTranslateCTM(context, 0, self.size.height)
    CGContextScaleCTM(context, 1.0, -1.0);
    CGContextSetBlendMode(context, CGBlendMode.Normal)

    let rect = CGRectMake(0, 0, self.size.width, self.size.height) as CGRect
    CGContextClipToMask(context, rect, self.CGImage)
    CGContextFillRect(context, rect)

    let newImage = UIGraphicsGetImageFromCurrentImageContext() as UIImage
    UIGraphicsEndImageContext()

    return newImage
  }
}

customTabBar.swift

override func viewDidLoad() {
  super.viewDidLoad()
  for item in self.tabBar.items! {
    item.image = item.selectedImage?.imageWithColor(unselectedColor).imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
    //In case you wish to change the font color as well
    let attributes = [NSForegroundColorAttributeName: unselectedColor]
    item.setTitleTextAttributes(attributes, forState: UIControlState.Normal)
  }
}
JoeGalind
  • 2,461
  • 1
  • 23
  • 28
7

I had to move the code into viewWillAppear because in viewDidLoad the images weren't set yet.

Swift 4 Translation

import Foundation
import UIKit

extension UIImage {
    func with(color: UIColor) -> UIImage {
        guard let cgImage = self.cgImage else {
            return self
        }
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        let context = UIGraphicsGetCurrentContext()!
        context.translateBy(x: 0, y: size.height)
        context.scaleBy(x: 1.0, y: -1.0)
        context.setBlendMode(.normal)
        let imageRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        context.clip(to: imageRect, mask: cgImage)
        color.setFill()
        context.fill(imageRect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext();
        return newImage
    }
}

class MYTabBarController: UITabBarController {

    let unselectedColor = UIColor(red: 108/255.0, green: 110/255.0, blue: 114/255.0, alpha: 1.0)
    let selectedColor = UIColor.blue()

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        // Unselected state colors
        for item in self.tabBar.items! {
            item.image = item.selectedImage!.with(color: unselectedColor).withRenderingMode(.alwaysOriginal)
        }
        UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : unselectedColor], for: .normal)

        // Selected state colors
        tabBar.tintColor = selectedColor
        UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : selectedColor], for: .selected)
    }
}
kgaidis
  • 10,753
  • 4
  • 58
  • 76
3

There is a new appearance API in iOS 13. To color tabbar item's icon and text correctly using Xcode 11.0 you can use it like this:

  if #available(iOS 13.0, *)
     {
        let appearance = tabBar.standardAppearance
        appearance.stackedLayoutAppearance.normal.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black]
        appearance.stackedLayoutAppearance.selected.titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.blue]
        appearance.stackedLayoutAppearance.normal.iconColor = UIColor.black
        appearance.stackedLayoutAppearance.selected.iconColor = UIColor.blue
        tabBar.standardAppearance = appearance
    } 
    else 
    {
        tabBar.unselectedItemTintColor = UIColor.black
        tabBar.tintColor = UIColor.blue
    }
Ved Sharma
  • 571
  • 3
  • 17
2

The new answer to do this programmatically as of iOS 10+ is to use the unselectedItemTintColor API. For example, if you have initialized your tab bar controller inside your AppDelegate, it would looks like the following:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        ...

        let firstViewController = VC1()
        let secondViewController = VC2()
        let thirdViewController = VC3()


        let tabBarCtrl = UITabBarController()
        tabBarCtrl.viewControllers = [firstViewController, secondViewController, thirdViewController]

        // set the color of the active tab
        tabBarCtrl.tabBar.tintColor = UIColor.white

        // set the color of the inactive tabs
        tabBarCtrl.tabBar.unselectedItemTintColor = UIColor.gray

        ...
    }
Anchor
  • 1,166
  • 15
  • 23
2

Or just without coding. Swift 4, Xcode 10.1.

  1. Add UITabBar on your View Controller using Interface Builder.
  2. Select the added view in the left panel.
  3. Type cmd + alt + 3 or just click Show the Identity Inspector in the right panel.
  4. In section User Defined Runtime Attributes click on plus button to add a new attribute and call it as unselectedItemTintColor (see here).
  5. Without leaving the section from the previous step (see number 4) under Type column choose Color type.
  6. Finally, set the necessary color under Value section.
  7. Compile your project
  8. Over. Congratulations.

enter image description here

shokuroff
  • 607
  • 1
  • 8
  • 16
1

Referring to the answer from here: UITabBar tint in iOS 7

You can set the tint color for selected and unselected tab bar buttons like this:

[[UIView appearanceWhenContainedIn:[UITabBar class], nil] setTintColor:[UIColor redColor]];
[[UITabBar appearance] setSelectedImageTintColor:[UIColor greenColor]];

The first line sets the unselected color - red in this example - by setting the UIView's tintColor when it's contained in a tab bar. Note that this only sets the unselected image's tint color - it doesn't change the color of the text below it.

The second line sets the tab bar's selected image tint color to green.

Community
  • 1
  • 1
Benkax
  • 779
  • 6
  • 7
1

Swift 4 version (Without implicitly unwrapping Optionals) :

UIImage+Overlay.swift

import UIKit

extension UIImage {
    func with(color: UIColor) -> UIImage? {
        guard let cgImage = self.cgImage else {
            return self
        }
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        if let context = UIGraphicsGetCurrentContext() {
            context.translateBy(x: 0, y: size.height)
            context.scaleBy(x: 1.0, y: -1.0)
            context.setBlendMode(.normal)
            let imageRect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
            context.clip(to: imageRect, mask: cgImage)
            color.setFill()
            context.fill(imageRect)
            if let newImage = UIGraphicsGetImageFromCurrentImageContext() {
                UIGraphicsEndImageContext();
                return newImage
            }
        }
        return nil;
    }
}


CustomTabBarController.swift

class CustomTabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()

        if #available(iOS 10.0, *) {
            self.tabBar.unselectedItemTintColor = UIColor.init(white: 1, alpha: 0.5)
        } else {
            // Fallback on earlier versions
            if let items = self.tabBar.items {
                let unselectedColor = UIColor.init(white: 1, alpha: 0.5)
                let selectedColor = UIColor.white
                // Unselected state colors
                for item in items {
                    if let selectedImage = item.selectedImage?.with(color: unselectedColor)?.withRenderingMode(.alwaysOriginal) {
                        item.image = selectedImage
                    }
                }
                UITabBarItem.appearance().setTitleTextAttributes([NSAttributedStringKey.foregroundColor : unselectedColor], for: .normal)

                // Selected state colors
                tabBar.tintColor = selectedColor
                UITabBarItem.appearance().setTitleTextAttributes([NSAttributedStringKey.foregroundColor : selectedColor], for: .selected)
            }
        }

        UITabBarItem.appearance().setTitleTextAttributes([NSAttributedStringKey.font: UIFont(name: "overpass-light", size: 12)!, NSAttributedStringKey.foregroundColor: UIColor.white], for: UIControlState.normal)
    }
}
AhmedZah
  • 1,153
  • 1
  • 7
  • 9
0

@JoeGalid's imageWithColor: solution with Xamarin:

using CoreGraphics;
using UIKit;

namespace Example
{
    public static class UIImageExtensions
    {
        public static UIImage ImageWithColor(this UIImage image, UIColor color)
        {
            UIGraphics.BeginImageContextWithOptions(image.Size, false, image.CurrentScale);

            color.SetFill();

            var context = UIGraphics.GetCurrentContext();

            context.TranslateCTM(0, image.Size.Height);
            context.ScaleCTM(1.0f, -1.0f);
            context.SetBlendMode(CoreGraphics.CGBlendMode.Normal);

            var rect = new CGRect(0, 0, image.Size.Width, image.Size.Height);
            context.ClipToMask(rect, image.CGImage);
            context.FillRect(rect);

            var newImage = UIGraphics.GetImageFromCurrentImageContext() as UIImage;
            UIGraphics.EndImageContext();

            return newImage;
        }
    }
}

Then utilize it when setting up the tab bar items:

var image = UIImage.FromBundle("name");
barItem.Image = image.ImageWithColor(UIColor.Gray).ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
barItem.SelectedImage = image.ImageWithColor(UIColor.Red).ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
JAM
  • 5,220
  • 27
  • 43
0

Unselected Color of Tabbar using swift

  1. Get Reference of your TabBarViewController
  2. Use the following code.

       [You tabbar controller name]?.tabBar.unselectedItemTintColor = [color name here]
    

Hope it will help.

Wajahat Hussain
  • 224
  • 2
  • 7