How to recreate the image filter UITabBarItem?

I am writing a custom replacement for UITabBar, and I would like to know how to recreate the filter that the inline implementation does with the UITabBarItem image โ€” blue on the selected tabs and a gray gradient on the unselected ones. I assume that it is a matter of using the alpha value of the original image as a mask and overlaying it on a pre-made blue (or any other) color image and the other in gray, but I would like to know what is the best code point approach.

Best

+4
source share
3 answers

Change: slightly fixed the blue filter
Edit2: cleaned the gray filter

I need code to perform these effects, so I wrote a couple of functions for them:

UIImage *grayTabBarItemFilter(UIImage *image) { int width = image.size.width, height = image.size.height; UIImage *result = image; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); if (colorSpace == NULL) { return result; } CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast); if (context == NULL) { CGColorSpaceRelease(colorSpace); return result; } CGFloat colors[8] = {80/255.0,80/255.0,80/255.0,1, 175/255.0,175/255.0,175/255.0,1}; CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2); CGContextDrawLinearGradient(context, gradient, CGPointMake(0,-(32-height)/2.0), CGPointMake(0,height+(32-height)/2.0), 0); CGGradientRelease(gradient); CGContextSetBlendMode(context, kCGBlendModeDestinationIn); CGContextDrawImage(context, CGRectMake(0,0,width,height), image.CGImage); CGImageRef newImage = CGBitmapContextCreateImage(context); if (newImage != NULL) { result = [UIImage imageWithCGImage:newImage]; CGImageRelease(newImage); } CGContextRelease(context); CGColorSpaceRelease(colorSpace); return result; } struct RGBA { unsigned char red; unsigned char green; unsigned char blue; unsigned char alpha; }; #define BLUE_ALPHA_THRESHOLD 128 #define BLUE_BRIGHTNESS_ADJUST 30 UIImage *blueTabBarItemFilter(UIImage *image) { int width = image.size.width, height = image.size.height; UIImage *result = image; CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); if (colorSpace == NULL) { return result; } CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast); if (context == NULL) { CGColorSpaceRelease(colorSpace); return result; } UIImage *gradient = [UIImage imageNamed:@"selection_gradient.png"]; CGContextDrawImage(context, CGRectMake(-(gradient.size.width - width) / 2.0, -(gradient.size.height - height) / 2.0, gradient.size.width, gradient.size.height), gradient.CGImage); CGContextSetBlendMode(context, kCGBlendModeDestinationIn); CGContextDrawImage(context, CGRectMake(0,0,width,height), image.CGImage); struct RGBA *pixels = CGBitmapContextGetData(context); if (pixels != NULL) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int offset = x+y*width; if (pixels[offset].alpha >= BLUE_ALPHA_THRESHOLD && ((x == 0 || x == width-1 || y == 0 || y == height-1) || (pixels[x+(y-1)*width].alpha < BLUE_ALPHA_THRESHOLD) || (pixels[x+1+y*width].alpha < BLUE_ALPHA_THRESHOLD) || (pixels[x+(y+1)*width].alpha < BLUE_ALPHA_THRESHOLD) || (pixels[x-1+y*width].alpha < BLUE_ALPHA_THRESHOLD))) { pixels[offset].red = MIN(pixels[offset].red + BLUE_BRIGHTNESS_ADJUST,255); pixels[offset].green = MIN(pixels[offset].green + BLUE_BRIGHTNESS_ADJUST,255); pixels[offset].blue = MIN(pixels[offset].blue + BLUE_BRIGHTNESS_ADJUST,255); } } } CGImageRef image = CGBitmapContextCreateImage(context); if (image != NULL) { result = [UIImage imageWithCGImage:image]; CGImageRelease(image); } } CGContextRelease(context); CGColorSpaceRelease(colorSpace); return result; } 

For the blue filter effect to work, you need to include this image in your project as "selection_gradient.png": selection_gradient.png
In addition, you can play around with definitions to get the effect that you like, I did not spend much time improving them, although they look good enough for me.

Of course, I donโ€™t know the exact filters that Apple applied, but I โ€œguessedโ€ them and they look good to me. I'm not sure if these features are compatible with the iPhone 4, because I only use them in the iPad app, but itโ€™s not difficult to change them to my liking.

+11
source

Try it; this is shorter:

 + (UIImage *)blendImageBlue:(UIImage *)senderImage { UIImage *image = [UIImage imageNamed:@"selection_gradient"]; CGSize newSize = CGSizeMake(senderImage.size.width, senderImage.size.height); UIGraphicsBeginImageContextWithOptions(newSize, NO, [UIScreen mainScreen].scale); [senderImage drawInRect:CGRectMake(0,0,newSize.width,newSize.height)]; [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height) blendMode:kCGBlendModeSourceAtop alpha:0.8]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

Edit: use @poiuy_qwert "selection_gradient.png"

+1
source

If you are interested in an exact copy of the UITabBarItem filter, try this solution. You do not need to include any additional images in your project.

I fully understand that this is a complete hack, and I do not do promises of compatibility in the future, but it works both in iOS 5 and iOS 6, as far as I can tell, and with the correct error handling I think this may be useful . Here it is:

 UIImage *grayTabBarItemFilter(UIImage *image) { UITabBar* bar = [[UITabBar alloc] init]; UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"" image:image tag:0]; [bar setItems:@[item]]; [[[[UIApplication sharedApplication] windows] lastObject] addSubview:bar]; UIImage* returnImage; for(UIView* view in bar.subviews) { for(UIView* small in view.subviews) { if([small respondsToSelector:@selector(image)]) { returnImage = [(UIImageView*)small image]; } } } [bar removeFromSuperview]; return returnImage ? returnImage : image; } UIImage *blueTabBarItemFilter(UIImage *image) { UITabBar* bar = [[UITabBar alloc] init]; UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"" image:image tag:0]; [bar setItems:@[item]]; [bar setSelectedItem:item]; [[[[UIApplication sharedApplication] windows] lastObject] addSubview:bar]; UIImage* returnImage; for(UIView* view in bar.subviews) { NSInteger count = 0; for(UIView* small in view.subviews) { if([small respondsToSelector:@selector(image)]) { count++; if(count > 1) { returnImage = [(UIImageView*)small image]; } } } } [bar removeFromSuperview]; return returnImage ? returnImage : image; } 

Again, I know this is not a good solution at best, but if you are interested in the perfect cue, here it is.

0
source

All Articles