18

Environment: - Xcode 6 beta 4 - Swift language - iOS Tabbed Application (default xCode project)

How can I change the default grey color of the tabs to something else? (Preferably globally)

As far as my research goes I need to somehow change the image rendering mode for each tab to Original rendering mode however I don't know how

Nick Germi
  • 401
  • 3
  • 6
  • 14

4 Answers4

55

Each (default) tab bar item consists of text and icon. It is pretty easy to change the text colors globally by specifying the appearance:

// you can add this code to you AppDelegate application:didFinishLaunchingWithOptions: 
// or add it to viewDidLoad method of your TabBarController class
UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.magentaColor()], forState:.Normal)
UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.redColor()], forState:.Selected)

With images situation is a little bit more complicated. You cannot define their appearance globally. You should redefine them in your TabBarController class. Add code bellow to viewDidLoad method of your TabBarController class:

for item in self.tabBar.items as [UITabBarItem] {
    if let image = item.image {
        item.image = image.imageWithColor(UIColor.yellowColor()).imageWithRenderingMode(.AlwaysOriginal)
    }
}

As we know there is no imageWithColor(...) method in UIImage class. So here is the extension implementation:

// Add anywhere in your app
extension UIImage {
    func imageWithColor(tintColor: UIColor) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)

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

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

        let newImage = UIGraphicsGetImageFromCurrentImageContext() as UIImage
        UIGraphicsEndImageContext()

        return newImage
    }
}

imageWithColor was borrowed from this answer: https://stackoverflow.com/a/24545102/3050466

Community
  • 1
  • 1
Keenle
  • 11,254
  • 2
  • 34
  • 46
  • - This will throw an error if one of the Tab items doesn't have an image. - I placed the extension inside my custom MyTabBarController class, just above `class MyTabBarController` line _(at first I tried to create a new target extension..)_ Cheers Nick – Nick Germi Jul 31 '14 at 17:47
  • You are right about `nil` image. I've updated the code with `if let` check. – Keenle Jul 31 '14 at 20:40
  • I'm having an issue with the above for-loop - I get `Braced block of statements is an unused closure` right at the opening square bracket where `[UITabBarItem]` is. Has the syntax changed since this answer was posted? – Jody Heavener Sep 07 '14 at 00:42
  • Just checked beta 7 release notes and verified in xCode 6 beta 7. Everything compiles fine without any errors. – Keenle Sep 07 '14 at 18:35
  • What about the text? How can I color the text of these items? – tester Oct 21 '14 at 14:07
  • What do you mean by "color the text"? I have answered how to change tab bar item text color, please look at the first two lines of code in my answer. – Keenle Oct 26 '14 at 11:31
  • 2
    I created tabbed application, an there is no TabBarController (file) class. I am going mad with this "super" IDE... – Dmitry Nov 27 '14 at 17:10
  • 1
    By default TabBarController in your storyboard is of type `UITabBarController`. You need to subclass it in your (lets call it) `MyTabBarController` class and add there code from the answer. And do not forget to go to the storyboard, select your TabBarController and set it class to `MyTabBarController`. So you should create `MyTabBarController` class. In answer it called TabBarController; probably I should rename it to avoid ambiguity. – Keenle Nov 27 '14 at 17:59
  • Awsome dude! I was looking for this really hard! – SwingerDinger Jan 07 '15 at 14:11
  • 6
    @Keenle: This changes the color of Normal images. What about Selected image? – Kashif Mar 31 '15 at 15:20
  • Perfect solution. Thanks a lot – Bonnke May 26 '15 at 15:39
  • When I run simulator, app is crashing, and it shows error in logs: fatal error: unexpectedly found nil while unwrapping an Optional value – Emm Nov 07 '15 at 20:31
  • I get "Use of unresolved identifier 'kCGBlendModeNormal'" error – Doug Amos Mar 24 '16 at 09:59
5

I don't have enough reputation for commenting the comments, but many are interested how to change the color of selected image

just add another if let check after

if let image = item.image

just like this:

if let selectedImage = item.selectedImage {
            item.selectedImage = selectedImage.imageWithColor(UIColor.yellowColor()).imageWithRenderingMode(.AlwaysOriginal)
        }

this solved the problem perfectly. And a little addition, since Swift 1.2 and Xcode 6.3.2 you need

for item in self.tabBar.items as! [UITabBarItem]

instead of

for item in self.tabBar.items as [UITabBarItem]

Hope that helps!

pulp
  • 1,498
  • 2
  • 13
  • 21
  • When I run simulator, app is crashing, and it shows error in logs: fatal error: unexpectedly found nil while unwrapping an Optional value – Emm Nov 07 '15 at 20:32
  • I think it's about you're using Xcode 7 and Swift 2.0 or above. This code is for Swift 1.2 and Xcode 6.3.2 Play around with optionals and unwrapping. – pulp Nov 09 '15 at 09:51
4

Swift 2.0

To change the default color for tab bar images, Add code bellow to viewDidLoad method of your TabBarController class:

for item in self.tabBar.items! as [UITabBarItem] {
    if let image = item.image {
      item.image = image.imageWithColor(UIColor.yellowColor()).imageWithRenderingMode(.AlwaysOriginal)
    }
}

Update the imageWithColor extension. Used with the above method and should be placed outside of your TabBarController class:

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

        let context = UIGraphicsGetCurrentContext()! as CGContextRef
        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)
        tintColor.setFill()
        CGContextFillRect(context, rect)

        let newImage = UIGraphicsGetImageFromCurrentImageContext() as UIImage
        UIGraphicsEndImageContext()

        return newImage
    }
}

No changes to the way text gets coloured but just for reference. Also should be added the code bellow to viewDidLoad:

// you can add this code to you AppDelegate application:didFinishLaunchingWithOptions: 
// or add it to viewDidLoad method of your TabBarController class
UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.magentaColor()], forState:.Normal)
UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.redColor()], forState:.Selected)
Eli Stone
  • 1,435
  • 3
  • 32
  • 56
  • What about the safety of this line `let context = UIGraphicsGetCurrentContext()! as CGContextRef`? Why can we be sure to use force unwrapping? – Andrej Jun 12 '16 at 21:29
3

Swift 3.0

To change the default color for tab bar images, Add code bellow to viewDidLoad method of your TabBarController class:

    for item in self.tabBar.items! as [UITabBarItem] {
        if let image = item.image {
            item.image = image.imageWithColor(tintColor: UIColor.yellow).withRenderingMode(.alwaysOriginal)
        }
    }

Update the imageWithColor extension. Used with the above method and should be placed outside of your TabBarController class:

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

    let context = UIGraphicsGetCurrentContext()! as CGContext
    context.translateBy(x: 0, y: self.size.height)
    context.scaleBy(x: 1.0, y: -1.0);
    context.setBlendMode(CGBlendMode.normal)

    let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)
    context.clip(to: rect, mask: self.cgImage!)
    tintColor.setFill()
    context.fill(rect)

    let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage
    UIGraphicsEndImageContext()

    return newImage
 }
}
Dasoga
  • 4,709
  • 3
  • 27
  • 37