如何重新创建 UITabBarItem 图像过滤器?
Posted
技术标签:
【中文标题】如何重新创建 UITabBarItem 图像过滤器?【英文标题】:How to recreate the UITabBarItem image filter? 【发布时间】:2010-09-24 03:58:03 【问题描述】:我正在编写一个自定义的 UITabBar 替换,我想知道如何重新创建内置实现对 UITabBarItem 图像所做的过滤器 - 蓝色在选定的选项卡上闪耀,在未选定的选项卡上呈现灰色渐变。我想这是使用源图像 alpha 值作为蒙版并用预制的蓝色(或任何颜色)闪亮图像覆盖它并且另一个变灰的问题,但我想知道什么是最好的方法代码观点。
最好的,
【问题讨论】:
您可以简单地为每个选项卡使用两个不同的图像(带有灰色和突出显示的内容),并在单击选项卡按钮时在它们之间切换...(当然,如果您正在创建这个,这是有效的自定义标签栏替换仅适用于您的应用,而不是作为可重用组件) 嗨 lukya,感谢您的反馈。为每个项目使用两个图像是显而易见的解决方案,但我想以代码方式完成它以使其可重用,就像你说的那样。 【参考方案1】:编辑:稍微修正了蓝色滤镜 Edit2:清理了灰色过滤器
我需要代码来实现这些效果,所以我为它们编写了几个函数:
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;
要使蓝色滤镜效果起作用,您需要将此图像作为“selection_gradient.png”包含在您的项目中: 此外,您可能想使用定义来获得您喜欢的效果,我没有花太多时间来完善它们,尽管它们对我来说已经足够好了。
当然,我不知道 Apple 应用的确切过滤器,但我“推测”了它们,它们看起来还不错。我不确定这些功能是否与 iPhone 4 兼容,因为我只在 iPad 应用程序中使用它们,但根据自己的喜好编辑它们并不难。
【讨论】:
我无法让这个滤镜在视网膜设备上工作。有没有人成功做到这一点?我试过 CGContextScaleCTM() 但这只会使图像变大一倍。 您只需将result = [UIImage imageWithCGImage:newImage];
更改为result = [UIImage imageWithCGImage:newImage scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
我实际上找到了一种精确复制 UITabBarItem 过滤器的方法。这有点骇人听闻,但它是像素完美的副本。稍后我会发布我的解决方案。
刚刚发布了我的答案。提供蓝色和灰色滤镜。【参考方案2】:
试试这个;它更短:
+ (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;
编辑:使用@poiuy_qwert 的“selection_gradient.png”
【讨论】:
尚未测试您的代码,但据我所知,这不会使图标的边缘变亮?【参考方案3】:如果您对 UITabBarItem 过滤器的精确副本感兴趣,请尝试此解决方案。您不需要在项目中包含任何额外的图像。
我完全清楚这完全是 hack,我不承诺未来的兼容性,但据我所知,它适用于 ios 5 和 iOS 6,并且我认为通过适当的错误处理它可能很有用。就是这样:
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;
同样,我知道这充其量只是一个不稳定的解决方案,但如果您对完美的复制品感兴趣,这里就是。
【讨论】:
以上是关于如何重新创建 UITabBarItem 图像过滤器?的主要内容,如果未能解决你的问题,请参考以下文章
如何减少 UITabBarItem 图像和文本之间的垂直填充?