iOS White to Transparent Gradient Layer is Gray

IosIphoneUiviewCalayerCagradientlayer

Ios Problem Overview


I have a CAGradientLayer inserted to the bottom of this small detail view that pops up at the bottom of the app. As you can see, I've set the colors from white to clear, but there's this strange gray tint that is showing up. Any ideas?

    // Set up detail view frame and gradient
    [self.detailView setFrame:CGRectMake(0, 568, 320, 55)];
    
    CAGradientLayer *layer = [CAGradientLayer layer];
    layer.frame = self.detailView.bounds;
    layer.colors = [NSArray arrayWithObjects:(id)[UIColor whiteColor].CGColor, (id)[UIColor clearColor].CGColor, nil];
    layer.startPoint = CGPointMake(1.0f, 0.7f);
    layer.endPoint = CGPointMake(1.0f, 0.0f);
    [self.detailView.layer insertSublayer:layer atIndex:0];

Here is the problematic view:

Here is the problematic view

Ios Solutions


Solution 1 - Ios

clearColor has a black color channel with an alpha of 0, so I had to use

[UIColor colorWithWhite:1 alpha:0]

and it works fine.

Solution 2 - Ios

In Swift This worked for me,

UIColor.white.withAlphaComponent(0).cgColor

Solution 3 - Ios

Worth pointing out that any other colour will work like this... using a combination of the two answers above....

Objective C

UIColor *colour = [UIColor redColor];
NSArray *colourArray = @[(id)[colour colorWithAlphaComponent:0.0f].CGColor,(id)colour.CGColor]
NSArray *locations = @[@0.2,@0.8];

CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.colors = colourArray;
gradientLayer.locations = locations;
gradientLayer.frame = self.frame;

[self.layer addSublayer:gradientLayer];

Swift 3

let colour:UIColor = .red
let colours:[CGColor] = [colour.withAlphaComponent(0.0).cgColor,colour.cgColor]
let locations:[NSNumber] = [0.2,0.8]

let gradientLayer = CAGradientLayer()
gradientLayer.colors = colours
gradientLayer.locations = locations
gradientLayer.frame = frame

layer.addSublayer(gradientLayer)

Solution 4 - Ios

Swift 3 Syntax,

UIColor(white: 1, alpha: 0).cgColor

Solution 5 - Ios

The answers above such as:

UIColor.white.withAlphaComponent(0).cgColor

and

UIColor(white: 1.0, alpha: 0.0).cgColor

should work in terms of getting a portion of your gradient to be clear (rather than the gray that OP is referring to). However, if you're still seeing a transparent white when you should be seeing a clear color, make sure the backgroundColor of the view to which you're applying the gradient is clear as well.

By default, that view's background color will likely be white (or a dark color if the device is in dark mode), so when you apply the gradient, the clear portion of it will be "blocked" by the view's backgroundColor itself. Set that to clear and you should be good to go.

Solution 6 - Ios

As many, I still got a gray colour despite using a clear white.

So I changed my approach and went for a mask rather than a gradient. End result is the same, well, better, since this one works in all situations, not just if you got a suitable background.

I did not try this code with IB, but hopefully it works as well. Just set backgroundColor and you are good to go.

@IBDesignable
class FadingView: UIView {
	
	@IBInspectable var startLocation: Double =   0.05 { didSet { updateLocations() }}
	@IBInspectable var endLocation:   Double =   0.95 { didSet { updateLocations() }}
	@IBInspectable var horizontalMode:  Bool =  false { didSet { updatePoints() }}
	@IBInspectable var diagonalMode:    Bool =  false { didSet { updatePoints() }}
	@IBInspectable var invertMode:      Bool =  false { didSet { updateColors() }}
	
	private let gradientLayerMask = CAGradientLayer()
	
	private func updatePoints() {
		if horizontalMode {
			gradientLayerMask.startPoint = diagonalMode ? CGPoint(x: 1, y: 0) : CGPoint(x: 0, y: 0.5)
			gradientLayerMask.endPoint   = diagonalMode ? CGPoint(x: 0, y: 1) : CGPoint(x: 1, y: 0.5)
		} else {
			gradientLayerMask.startPoint = diagonalMode ? CGPoint(x: 0, y: 0) : CGPoint(x: 0.5, y: 0)
			gradientLayerMask.endPoint   = diagonalMode ? CGPoint(x: 1, y: 1) : CGPoint(x: 0.5, y: 1)
		}
	}
	
	private func updateLocations() {
		gradientLayerMask.locations = [startLocation as NSNumber, endLocation as NSNumber]
	}
	
	private func updateSize() {
		gradientLayerMask.frame = bounds
	}
	
	private func updateColors() {
		gradientLayerMask.colors = invertMode ? [UIColor.white.cgColor, UIColor.clear.cgColor] : [UIColor.clear.cgColor, UIColor.white.cgColor]
	}
	
	private func commonInit() {
		layer.mask = gradientLayerMask
	}
	
	override init(frame: CGRect) {
		super.init(frame: frame)
		commonInit()
	}
	
	required init?(coder aDecoder: NSCoder) {
		super.init(coder: aDecoder)
		commonInit()
	}
	
	override func layoutSubviews() {
		super.layoutSubviews()
		updatePoints()
		updateLocations()
		updateSize()
		updateColors()
	}
}

Solution 7 - Ios

It's worth noting that to handle white/black (or really any color with light/dark appearances) gradients based on light/dark mode in iOS 13 that this approach also works with the new system colors:

gradientLayer.colors = [
    UIColor.systemBackground.cgColor,
    UIColor.systemBackground.withAlphaComponent(0).cgColor] 

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEric GaoView Question on Stackoverflow
Solution 1 - IosEric GaoView Answer on Stackoverflow
Solution 2 - IosMohammad Zaid PathanView Answer on Stackoverflow
Solution 3 - IosMagooView Answer on Stackoverflow
Solution 4 - IosStuart CasarottoView Answer on Stackoverflow
Solution 5 - IosBrian SachettaView Answer on Stackoverflow
Solution 6 - IosTancrede ChazalletView Answer on Stackoverflow
Solution 7 - IosJakeView Answer on Stackoverflow