如何重新创建 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 图像的大小

如何在 UITabbaritem 上设置图像?

如何减少 UITabBarItem 图像和文本之间的垂直填充?

UITabBarItem 图像颜色为灰色,而原始图像为白色

如何在 UITabBarItem 上设置不同的未选择图像和文本颜色

如何更改特定 UITabBarItem 的背景 [关闭]