如何设置UIImage的不透明度/ alpha?


81

我知道您可以使用UIImageView来做到这一点,但是可以对UIImage做到吗?我想让UIImageView的动画图像array属性成为相同图像但不透明的数组。有什么想法吗?

Answers:


122

我只需要这样做,但认为史蒂文的解决方案很慢。希望可以使用图形硬件。在UIImage上创建一个类别:

- (UIImage *)imageByApplyingAlpha:(CGFloat) alpha {
    UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0f);

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect area = CGRectMake(0, 0, self.size.width, self.size.height);

    CGContextScaleCTM(ctx, 1, -1);
    CGContextTranslateCTM(ctx, 0, -area.size.height);

    CGContextSetBlendMode(ctx, kCGBlendModeMultiply);

    CGContextSetAlpha(ctx, alpha);

    CGContextDrawImage(ctx, area, self.CGImage);

    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return newImage;
}

3
甚至不记得我为什么需要这个:)
马蒂

很好的解决方案!谢谢尼克!
Christopher

1
只需确保在主线程上调用UIGraphicsBeginImageContextWithOptions,因为背景渲染将是不可预测的。
史蒂文·韦尔特玛

1
根据Apple的说法,自iOS 4及更高版本开始,您可以在任何线程上调用UIGraphicsBeginImageContextWithOptions。
蚂蚁

6
效果很好,非常感谢。对于围绕iOS开发进行物流的其他新手,以下是为UIImage创建类别的步骤。1.右键单击项目主管,然后选择“新建文件”。2.在出现的屏幕中,选择Objective-C类别文件类型。3.在.m文件中添加答案的代码,并在.h文件中添加方法的声明。4.在使用透明图像的文件中,#import文件。5.在UIImage的实例上使用方法imageByApplyingAlpha。
Danny

79

设置显示它的视图的不透明度。

UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithName:@"SomeName.png"]];
imageView.alpha = 0.5; //Alpha runs from 0.0 to 1.0

在动画中使用它。您可以在动画中更改Alpha的持续时间。

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
//Set alpha
[UIView commitAnimations];

是的,我当时想我可能需要使用计时器来执行此操作以不断更改不透明度,只是认为为动画图像array属性设置一个数组会更容易,这样它就可以自己进行动画处理。
马蒂

您可以使用动画委托像心跳一样对其进行“内”和“外”动画处理。不要使用计时器,动画将平滑地更改Alpha。祝好运。
Mats Stijlaart

3
这仅在开发人员使用UIImageView时有效。问题清楚地表明并非如此。
罗尔·于尔塔2014年

1
这与在CALayer中显示的UIImage一起使用,只需要设置layer.opacity而不用完全修改图像。谢谢Mats!
克里斯

大!作品上UIButton,正是我需要的。
NecipAllef '16

52

基于Alexey Ishkov的答案,但基于Swift

我使用了UIImage类的扩展。

斯威夫特2:

UIImage扩展:

extension UIImage {
    func imageWithAlpha(alpha: CGFloat) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        drawAtPoint(CGPointZero, blendMode: .Normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

使用方法:

let image = UIImage(named: "my_image")
let transparentImage = image.imageWithAlpha(0.5)

迅捷3/4/5:

请注意,此实现返回一个可选的UIImage。这是因为在Swift 3中UIGraphicsGetImageFromCurrentImageContext现在返回了一个可选的。如果上下文为nil或未使用创建的上下文,则此值为nil UIGraphicsBeginImageContext

UIImage扩展:

extension UIImage {
    func image(alpha: CGFloat) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        draw(at: .zero, blendMode: .normal, alpha: alpha)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
}

使用方法:

let image = UIImage(named: "my_image")
let transparentImage = image?.image(alpha: 0.5)

我更喜欢这个Swift 3版本。
AechoLiu

谢谢。它在Swift 4中的工作原理相同,我更新了答案以反映这一点。
zeeshan '18

布拉沃先生,布拉沃
瑞安·布罗迪

17

有更简单的解决方案:

- (UIImage *)tranlucentWithAlpha:(CGFloat)alpha
{
    UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
    [self drawAtPoint:CGPointZero blendMode:kCGBlendModeNormal alpha:alpha];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

1
可能应该是公认的答案。最快/最有效的方法来获得结果
Will Von Ullrich

4

我意识到这已经很晚了,但是我需要这样的东西,所以我想出了一种快速而肮脏的方法来做到这一点。

+ (UIImage *) image:(UIImage *)image withAlpha:(CGFloat)alpha{

    // Create a pixel buffer in an easy to use format
    CGImageRef imageRef = [image CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    UInt8 * m_PixelBuf = malloc(sizeof(UInt8) * height * width * 4);

    NSUInteger bytesPerPixel = 4;
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);

    //alter the alpha
    int length = height * width * 4;
    for (int i=0; i<length; i+=4)
    {
        m_PixelBuf[i+3] =  255*alpha;
    }


    //create a new image
    CGContextRef ctx = CGBitmapContextCreate(m_PixelBuf, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGImageRef newImgRef = CGBitmapContextCreateImage(ctx);  
    CGColorSpaceRelease(colorSpace);
    CGContextRelease(ctx);  
    free(m_PixelBuf);

    UIImage *finalImage = [UIImage imageWithCGImage:newImgRef];
    CGImageRelease(newImgRef);  

    return finalImage;
}

2
更好的名字是setImage:withAlpha:
亚历山大

8
设置通常是指属性,以某种方式更改接收者的状态。命名会更好image:withAlpha:吗?
乔纳森。

2
是的 同样,调用set会应用设置传入的相同对象的方法,而不是返回新图像。
系统

4

嘿,感谢Xamarin用户!:)在这里它被翻译成c#

//***************************************************************************
public static class ImageExtensions
//***************************************************************************
{
    //-------------------------------------------------------------
    public static UIImage WithAlpha(this UIImage image, float alpha)  
    //-------------------------------------------------------------
        {
        UIGraphics.BeginImageContextWithOptions(image.Size,false,image.CurrentScale);
        image.Draw(CGPoint.Empty, CGBlendMode.Normal, alpha);
        var newImage = UIGraphics.GetImageFromCurrentImageContext();
        UIGraphics.EndImageContext();
        return newImage;
        }

}

用法示例:

var MySupaImage = UIImage.FromBundle("opaquestuff.png").WithAlpha(0.15f);

1

与其他人相同的结果,不同的风格:

extension UIImage {

    func withAlpha(_ alpha: CGFloat) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { _ in
            draw(at: .zero, blendMode: .normal, alpha: alpha)
        }
    }

}

1

斯威夫特5:

extension UIImage {
  func withAlphaComponent(_ alpha: CGFloat) -> UIImage? {
    UIGraphicsBeginImageContextWithOptions(size, false, scale)
    defer { UIGraphicsEndImageContext() }

    draw(at: .zero, blendMode: .normal, alpha: alpha)
    return UIGraphicsGetImageFromCurrentImageContext()
  }
}

0

如果您正在试验Metal渲染,并且要在第一个答复中提取由imageByApplyingAlpha生成的CGImage,则最终可能会得到比您期望的更大的Metal渲染。在试用Metal时,您可能需要更改imageByApplyingAlpha中的一行代码:

    UIGraphicsBeginImageContextWithOptions (self.size, NO, 1.0f);
//  UIGraphicsBeginImageContextWithOptions (self.size, NO, 0.0f);

如果您使用的缩放比例为3.0的设备(如iPhone 11 Pro Max),则上面显示的0.0缩放比例将为您提供比预期大三倍的CGImage。将比例因子更改为1.0应该避免任何缩放。

希望此答复将为初学者节省很多麻烦。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.