Currently, I have the following onboarding screen.
I would like to apply some gradient effect, on the bottom of the image.
I want to apply transparent color to black color transition, from 70% (0.7) height of the image, until 100% (1.0) height of the image.
It should look something like the following sample (Look at the bottom of the screen)
I thought the following code might work (I change from clear color to red color, for better visualization on what happens behind the scene)
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Remove any existing gradient layers to prevent stacking
demoImageView.layer.sublayers?.forEach { layer in
if layer is CAGradientLayer {
layer.removeFromSuperlayer()
}
}
let gradientLayer = CAGradientLayer()
// Set the gradient colors - from clear to black.
// We use red so that we can have better visualization to see what's going on.
gradientLayer.colors = [UIColor.red.cgColor, UIColor.black.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.7)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
// Set the frame of the gradient layer to match the imageView's bounds
gradientLayer.frame = demoImageView.bounds
// Add the gradient layer to the imageView's layer
demoImageView.layer.addSublayer(gradientLayer)
}
The whole image is covered by red (clear color) and black is not seen.
Does anyone has idea what's wrong with my code. I have try to experiment with gradientLayer.locations.
But, still not able to achieve what I want 😔
Thank you.
This is quite a common need. Let's invent a gradient view. It covers the main view from the bottom upwards, only to the height of the gradient. The view "hosts" a gradient layer, not as a sublayer, but as its layer, by setting the view's layerClass
to CAGradientLayer.self
. We have then but to configure the view's layer, as follows:
Its startPoint
and endPoint
should be (x: 0.5, y: 0)
and (x: 0.5, y: 1)
repectively. This will give us a vertical linear gradient flowing from top to bottom.
Its colors should be (for our first attempt) an array of two CGColors, one for clear and one for black.
class GradientView: UIView {
override class var layerClass: AnyClass { CAGradientLayer.self }
override init(frame: CGRect) {
super.init(frame: frame)
isOpaque = false
if let gradient = self.layer as? CAGradientLayer {
gradient.startPoint = .init(x: 0.5, y: 0)
gradient.endPoint = .init(x: 0.5, y: 1)
gradient.colors = [UIColor.clear.cgColor, UIColor.black.cgColor]
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
To test it, let's insert one at the bottom of a view controller's view:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let v = GradientView()
v.frame = CGRect(x: 0, y: self.view.bounds.height - 100, width: self.view.bounds.width, height: 100)
self.view.addSubview(v)
self.view.backgroundColor = .green
}
Result:
Now, if you don't quite like that, you can play with the specs of the CAGradientLayer. For instance, we could add some more room to the clear part by having three locations (instead of the default, which is two), at let's say 0.0, 0.3, and 1.0; the colors would then be an array of three colors, clear, clear, and black. We could also add a fourth location to get more black earlier on.
gradient.locations = [0.0, 0.3, 0.9, 1.0]
gradient.colors = [UIColor.clear.cgColor, UIColor.clear.cgColor, UIColor.black.cgColor, UIColor.black.cgColor]
Result:
That should be enough of an example to let you tweak away to your heart's content. In real life, of course, you should also generalize this view with a nice API of methods and properties so that at the call site the client can easily change the colors etc.