Transparency gradient on UIImageView
Asked Answered
A

4

6

I would imagine what I am trying to do is quite simple, but I can't seem to figure it out. I know how to apply a gradient on a UIImage using an UIImageView, but that is not what I want. What I want to do is, while keeping the image bounds, is to fade out the top half of a UIImage so it is fully transparent. I want to be able to see the view behind the UIImage with the bottom half of the image still fully visible (not opaque).

Any ideas? Any help would be greatly appreciated.

Actinochemistry answered 4/6, 2014 at 0:8 Comment(0)
B
11

The easiest way to do this is to use a CAGradientLayer as a layer mask—in other words, use its opacity to determine the opacity of the layer it’s attached to. Something along these lines should do the trick:

CALayer *imageViewLayer = theImageView.layer;
CAGradientLayer *maskLayer = [CAGradientLayer layer];
maskLayer.colors = @[ (id)([UIColor blackColor].CGColor), (id)([UIColor clearColor].CGColor) ]; // gradient from 100% opacity to 0% opacity (non-alpha components of the color are ignored)
// startPoint and endPoint (used to position/size the gradient) are in a coordinate space from the top left to bottom right of the layer: (0,0)–(1,1)
maskLayer.startPoint = CGPointMake(0, 0.5); // middle left
maskLayer.endPoint = CGPointMake(0, 0); // top left
maskLayer.frame = imageViewLayer.bounds; // line it up with the layer it’s masking
imageViewLayer.mask = maskLayer;
Baro answered 4/6, 2014 at 0:26 Comment(2)
Thanks I tried this but I want to work directly with UIImages, would you have any guidance on that?Actinochemistry
Why? If you need to adjust the image itself you’ll have to go through Core Graphics, but this is the most straightforward approach.Baro
I
2

Swift 5.0 (and 4.2) version of Noah's answer:

let maskLayer = CAGradientLayer(layer: theImageView.layer)
maskLayer.colors = [UIColor.black.cgColor, UIColor.clear.cgColor]
maskLayer.startPoint = CGPoint(x: 0, y: 0.5)
maskLayer.endPoint = CGPoint(x: 0, y: 0)
maskLayer.frame = theImageView.bounds
theImageView.layer.mask = maskLayer
Ixtle answered 7/4, 2019 at 19:50 Comment(0)
A
1

It's very important to don't forget remove sublayer from image sublayers else cells will have more than 1 sublayer and will be fill by color not gradient. I have tried to do this on awakeFromNib, but it works bad - container width is unknown when awakeFromNib is called, so you can get non fullwidth gradient.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *simpleTableIdentifier = @"actionsTableCell";

    actionsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier forIndexPath:indexPath];
    CAGradientLayer *gradient = [CAGradientLayer layer];
    gradient.frame = cell.myImage.bounds;
    gradient.colors = @[(id)[[UIColor clearColor] CGColor],
                    (id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:.5] CGColor],
                    (id)[[UIColor colorWithRed:0 green:0 blue:0 alpha:1] CGColor]];
    [[cell.myImage.layer.sublayers objectAtIndex:0] removeFromSuperlayer];
    [cell.myImage.layer addSublayer:gradient];

    cell.header.text = [recipes objectAtIndex:indexPath.row];
    return cell;
}
Annihilation answered 5/5, 2015 at 11:31 Comment(0)
R
0

Try the following amendment to Noah's code below. In effect the enumeration checks if there are defined mask layers as opposed to using the default layer.mask CALayer. I came across an interesting issue with UIImageViews trying to set this value.

    CALayer *_layerImage = _imageViewBackground.layer;
    CGRect _rect = _imageViewBackground.bounds;

    __block CAGradientLayer *_maskLayer = nil;

    [_layerImage.sublayers enumerateObjectsUsingBlock:^(CALayer * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        if ([obj isKindOfClass:[CAGradientLayer class]]) {
            _maskLayer = (CAGradientLayer*) obj;
            *stop = YES;
        }
    }];

    BOOL _found = YES;
    if (!_maskLayer) {
        _maskLayer = [CAGradientLayer layer];
        _found = NO;
    }

    _maskLayer.colors = @[ (id)([UIColor redColor].CGColor), (id)([UIColor clearColor].CGColor) ]; // gradient from 100% opacity to 0% opacity (non-alpha components of the color are ignored)
    // startPoint and endPoint (used to position/size the gradient) are in a coordinate space from the top left to bottom right of the layer: (0,0)–(1,1)
    _maskLayer.startPoint = CGPointMake(0, 0);
    _maskLayer.endPoint = CGPointMake(1, 1);
    _maskLayer.frame = _rect; // line it up with the layer it’s masking

    dispatch_async(dispatch_get_main_queue(), ^{
        if (!_found) {
            [_layerImage addSublayer:_maskLayer];
        }
    });

Hope that helps!

Roundsman answered 18/3, 2017 at 6:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.