element119 element119 - 1 month ago 16
iOS Question

Change only one specific UITabBarItem tint color

It is well known that the tint color of selected (or active) items in a UITabBarController can be easily changed, here is an example:

myBarController.tabBar.tintColor = [UIColor redColor];


In this instance, any tab bar item in tabBar will have a red tint once it is made active. Again, this applies to all of the items in this tab bar.

How can the active tint color be different between other tab bar items in the same bar? For example, one item might have a red tint while selected, while another might have a blue tint.

I am aware that this can probably be solved by redrawing and subclassing the entire tab bar. However, this is the only change I need, and it seems overkill to do so. I'm not trying to change the style or how the items are rendered in any way, just to make that style different between different items.

I haven't seen any answers to this question anywhere that are relevant to the updates in iOS 7 and 8.

Answer

I did some experimenting and based on this answer, found a way to do what I want without subclassing UITabBarItem or UITabBar!

Basically, the idea is to create a method of UIImage that mimics the tint mask behavior of UITabBar, while rendering it in its "original" form and avoiding the native tint mask.

All you have to do is create a new instance method of UIImage that returns an image masked with the color we want:

@interface UIImage(Overlay)
- (instancetype)tabBarImageWithCustomTint:(UIColor *)tintColor;
@end

@implementation UIImage(Overlay)

- (instancetype)tabBarImageWithCustomTint:(UIColor *)tintColor
{
    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);
    [tintColor setFill];
    CGContextFillRect(context, rect);
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    newImage = [newImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
    return newImage;
}
@end

This is a fairly straightforward version of the code in the answer that I posted, with one exception- the returned image has its rendering mode set to always original, which makes sure that the default UITabBar mask won't be applied. Now, all that is needed is to use this method when editing the tab bar item:

navController.tabBarItem = [[UITabBarItem alloc] initWithTitle:@"title" image:normal_image selectedImage:[selected_image tabBarImageWithCustomTint:[UIColor redColor]]];

Needless to say, selected_image is the normal image one gets from UIImage imageNamed: and the [UIColor redColor can be replaced with any color one desires.