如何在iOS中使用渐变创建叠加颜色

时间:2016-01-13 14:15:03

标签: ios objective-c iphone uiimageview cgcolor

背景信息:我有UIImageView。我通过以下方式在其图像上添加了叠加颜色:

UIGraphicsBeginImageContext(initialImage.size);
[initialImage drawInRect:CGRectMake(0, 0, initialImage.size.width, initialImage.size.height) blendMode:kCGBlendModeNormal alpha:alphaValue];
UIBezierPath * path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, initialImage.size.width, initialImage.size.height)];
[overlayColor setFill];
[path fillWithBlendMode:kCGBlendModeMultiply alpha:1];
finalImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

[self setImage:finalImage];

我仍然希望将其添加为叠加颜色,但我希望它具有渐变效果。我一直试图找到一种方法来做到这一点,但并没有真正成功。我想,用渐变添加叠加颜色的方法是错误的?我不知道该怎么做。我尝试将CGGradientLayer作为sublayer添加到UIImageView,但它不起作用。

我考虑添加UIView并将backgroundColor设置为overlayColor,然后将CGGradientLayer添加为sublayer UIView它作为subview添加到UIImageView但是,我们不应该将subviews添加到UIImageViews

有人可以帮我这个吗?也许我应该改变我的做法?

指出我正确的方向也会很棒!

如果这篇文章还不完全清楚的话,我期待你的回复和道歉!

提前感谢您的帮助!

修改:CGGradientLayer

的代码
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = self.frame;

UIColor *colorOne = [UIColor colorFromHex:self.feedColor withAlpha:(alphaValue * 0.7)];
UIColor *colorTwo = [UIColor colorFromHex:self.feedColor withAlpha:(alphaValue * 1.0)];

gradient.colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, (id)colorTwo.CGColor, nil];

[self.layer insertSublayer:gradient atIndex:0];

3 个答案:

答案 0 :(得分:1)

我会使用Core Graphics来获取输入图像,对其应用渐变叠加,然后将其传递到UIImageView。这样的事情应该达到预期的效果:

- (UIImage *)imageWithGradientOverlay:(UIImage *)sourceImage color1:(UIColor *)color1 color2:(UIColor *)color2 gradPointA:(CGPoint)pointA gradPointB:(CGPoint)pointB {

    CGSize size = sourceImage.size;

    // Start context
    UIGraphicsBeginImageContext(size);
    CGContextRef c = UIGraphicsGetCurrentContext();

    // Draw source image into context
    CGContextDrawImage(c, (CGRect){CGPointZero, size}, sourceImage.CGImage);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGFloat gradLocs[] = {0, 1};
    NSArray *colors = @[(id)color1.CGColor, (id)color2.CGColor];

    // Create a simple linear gradient with the colors provided.
    CGGradientRef grad = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, gradLocs);
    CGColorSpaceRelease(colorSpace);

    // Draw gradient with multiply blend mode over the source image
    CGContextSetBlendMode(c, kCGBlendModeMultiply);
    CGContextDrawLinearGradient(c, grad, pointA, pointB, 0);
    CGGradientRelease(grad);

    // Grab resulting image from context
    UIImage *resultImg = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return resultImg;
}

这是sourceImage是输入图片的地方,color1color2是您的渐变颜色,gradPointAgradPointB是您的线性渐变终点(在Core Graphics坐标系中,左下角是(0,0))。

通过这种方式,您可以节省不得不使用图层。如果您经常使用不同的颜色重新绘制,那么您可能需要采用使用图层的方法。

答案 1 :(得分:1)

如果您正在寻找更具动态性的方法,那么我会继承CALayer而不是UIImageView。因此,你需要这样的东西:

@interface gradientImageLayer : CALayer

- (instancetype)initWithFrame:(CGRect)frame;

@end

@implementation gradientImageLayer

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super init]) {

        self.opaque = YES; // Best for performance, but you if you want the layer to have transparency, then remove.

        UIImage *i = [UIImage imageNamed:@"foo2.png"]; // Replace with your image

        self.frame = frame;

        self.contentsScale = [UIScreen mainScreen].nativeScale;
        self.contents = (__bridge id _Nullable)(i.CGImage);

        // Your code for the CAGradientLayer was indeed correct.
        CAGradientLayer *gradient = [CAGradientLayer layer];
        gradient.frame = frame;

        // Add whatever colors you want here.
        UIColor *colorOne = [UIColor colorWithRed:1 green:1 blue:0 alpha:0.1];
        UIColor *colorTwo = [UIColor colorWithRed:0 green:1 blue:1 alpha:0.2];

        gradient.colors = @[(id)colorOne.CGColor, (id)colorTwo.CGColor]; // Literals read far nicer than a clunky [NSArray arrayWith.... ]

        [self addSublayer:gradient];        
    }

    return self;
}

@end

此方法的缺点是您无法应用不同的混合模式。我在CALayer上应用混合模式的唯一解决方案是通过Core Graphics,但随后我的原始答案会更好。

答案 2 :(得分:0)

我将在此question

中发布协作解决方案

此类别允许您使用任何混合模式(乘法,法线等)和CoreGraphics添加颜色叠加或渐变颜色叠加

快捷键4:

extension UIImage {

    //creates a static image with a color of the requested size
    static func fromColor(color: UIColor, size: CGSize) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()
        context?.setFillColor(color.cgColor)
        context?.fill(rect)
        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }

    func blendWithColorAndRect(blendMode: CGBlendMode, color: UIColor, rect: CGRect) -> UIImage {

        let imageColor = UIImage.fromColor(color: color, size:self.size)

        let rectImage = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)

        UIGraphicsBeginImageContextWithOptions(self.size, true, 0)
        let context = UIGraphicsGetCurrentContext()

        // fill the background with white so that translucent colors get lighter
        context!.setFillColor(UIColor.white.cgColor)
        context!.fill(rectImage)

        self.draw(in: rectImage, blendMode: .normal, alpha: 1)
        imageColor.draw(in: rect, blendMode: blendMode, alpha: 0.8)

        // grab the finished image and return it
        let result = UIGraphicsGetImageFromCurrentImageContext()

        //self.backgroundImageView.image = result
        UIGraphicsEndImageContext()
        return result!

    }
    //creates a static image with a gradient of colors of the requested size
    static func fromGradient(colors: [UIColor], locations: [CGFloat], horizontal: Bool, size: CGSize) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)

        UIGraphicsBeginImageContext(rect.size)
        let context = UIGraphicsGetCurrentContext()

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let cgColors = colors.map {$0.cgColor} as CFArray
        let grad = CGGradient(colorsSpace: colorSpace, colors: cgColors , locations: locations)

        let startPoint = CGPoint(x: 0, y: 0)
        let endPoint = horizontal ? CGPoint(x: size.width, y: 0) : CGPoint(x: 0, y: size.height)

        context?.drawLinearGradient(grad!, start: startPoint, end: endPoint, options: .drawsAfterEndLocation)

        let img = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return img!
    }

    func blendWithGradientAndRect(blendMode: CGBlendMode, colors: [UIColor], locations: [CGFloat], horizontal: Bool = false, alpha: CGFloat = 1.0, rect: CGRect) -> UIImage {

        let imageColor = UIImage.fromGradient(colors: colors, locations: locations, horizontal: horizontal, size: size)

        let rectImage = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height)

        UIGraphicsBeginImageContextWithOptions(self.size, true, 0)
        let context = UIGraphicsGetCurrentContext()

        // fill the background with white so that translucent colors get lighter
        context!.setFillColor(UIColor.white.cgColor)
        context!.fill(rectImage)

        self.draw(in: rectImage, blendMode: .normal, alpha: 1)
        imageColor.draw(in: rect, blendMode: blendMode, alpha: alpha)

        // grab the finished image and return it
        let result = UIGraphicsGetImageFromCurrentImageContext()

        //self.backgroundImageView.image = result
        UIGraphicsEndImageContext()
        return result!

    }
}

示例渐变:

let  newImage = image.blendWithGradientAndRect(blendMode: .multiply,
                                           colors: [.red, .white],
                                           locations: [0, 1],
                                           horizontal: true,
                                           alpha: 0.8,
                                           rect: imageRect)

单色示例:

let newImage = image.blendWithColorAndRect(blendMode: .multiply, color: .red, rect: imageRect)