I am trying to add some gradient to a view in Xcode and for simplicity I tried to add my method as an extension to UIView:
extension UIView {
func applyGradient() {
let gradient = CAGradientLayer()
gradient.colors = [UIColor(hex: "F5FF8C").cgColor,
UIColor(hex: "F1F99D").cgColor,
UIColor(hex: "FDFFE0").cgColor]
gradient.locations = [0.0, 0.5, 1.0]
self.layer.insertSublayer(gradient, at: 0)
}
}
But apparently this doesn't work when I call it in my viewDidLoad:
self.myView.applyGradient()
Can someone point to me what am I doing wrong ?
In the question, you haven't set the frame at all. In the comment, your frame was not set correctly. This is the code that should work properly:
extension UIView {
func applyGradient() {
let gradient = CAGradientLayer()
gradient.colors = [UIColor.red.cgColor,
UIColor.green.cgColor,
UIColor.black.cgColor] // your colors go here
gradient.locations = [0.0, 0.5, 1.0]
gradient.frame = self.bounds
self.layer.insertSublayer(gradient, at: 0)
}
}
With your code:
With the modified code:
Explanation
gradient.frame.size = self.frame.size doesn't work, while gradient.frame = self.bounds does, because the frame attribute contains both the location and the size of the view, and even if you set the gradient's frame size, you do not specify the location of the gradient... So the gradient is never actually added to the view. By setting the frame attribute directly to the bounds of the view, you also add the location of the gradient in the view.
Related
I've got this function defined in an extension of UIView which I use to set the gradient background on a UIView:
func setGradientBackground(colorTop: UIColor, colorBottom: UIColor, withCornerRadius : CGFloat){
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [colorBottom.cgColor, colorTop.cgColor]
gradientLayer.startPoint = CGPoint(x: 0.5, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 0.5, y: 0.0)
gradientLayer.locations = [0, 1]
gradientLayer.frame = bounds
gradientLayer.cornerRadius = withCornerRadius
layer.insertSublayer(gradientLayer, at: 0)
}
It is used as follows:
view.setGradientBackground(colorTop: UIColor.blue, colorBottom: UIColor.red, withCornerRadius: 10)
The problem is, if I have already called this function once on a view, the second time I call it, it does not do anything. I suspect this is caused by the subLayer persisting from the previous insertion.
I've tried adding:
if layer.sublayers?.count ?? 0 > 0 {
layer.sublayers?.remove(at: 0)
}
to the top of that function, but that causes by code to crash with a BAD_INSTRUCTION exception.
You can get the Gradient layer and can remove from view anywhere you want to ... Not just by adding it again you remove it..
if let gradientLayer = (yourView.layer.sublayers?.compactMap { $0 as? CAGradientLayer })?.first {
print("gradientLayer is presnet")
gradientLayer.removeFromSuperlayer()
} else {
print("its not added on layer yet")
}
The easiest option would be to check to see if the layer's sublayer is a gradient layer. This isn't perfectly safe because if you happen to have another gradient layer at index 0 of the sublayers, it will change the incorrect sublayer.
func setGradientBackground(colorTop: UIColor, colorBottom: UIColor, withCornerRadius cornerRadius: CGFloat) {
let gradientLayer = layer.sublayers?.first as? CAGradientLayer ?? CAGradientLayer()
// The rest of your existing layer customization code here
guard gradientLayer.superlayer != self else {
return
}
layer.sublayers?.insertSublayer(gradientLayer, at: 0)
}
Here is what I am trying to do:
The screenshot is taken from Iphone:
This is my code:
#IBOutlet weak var viewBottomBorder: UIView!
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 0.5, y: 0.0)
gradient.endPoint = CGPoint(x: 0.5, y: 1.0)
let whiteColor = UIColor.black
gradient.colors = [whiteColor.withAlphaComponent(0.0).cgColor, whiteColor.withAlphaComponent(1.0), whiteColor.withAlphaComponent(1.0).cgColor]
gradient.locations = [NSNumber(value: 0.0),NSNumber(value: 0.2),NSNumber(value: 1.0)]
gradient.frame = viewBottomBorder.bounds
viewBottomBorder.layer.mask = gradient
Question: How to show same text in white color with gradient?
Can someone please explain to me how to solve this , i've tried to solve this issue but no results yet.
Any help would be greatly appreciated.
Thanks in advance.
You need to start your gradient at the top, because it's darker at the top. So x should be have max alpha. Then as y increases reduce the alpha.
Try this:
let gradient = CAGradientLayer()
gradient.startPoint = CGPoint(x: 1.0, y: 0.0)
gradient.endPoint = CGPoint(x: 0.0, y: 1.0)
let whiteColor = UIColor.black
gradient.colors = [whiteColor.withAlphaComponent(1.0).cgColor, whiteColor.withAlphaComponent(1.0), whiteColor.withAlphaComponent(0.0).cgColor]
gradient.locations = [NSNumber(value: 1.0),NSNumber(value: 0.7),NSNumber(value: 0.0)]
gradient.frame = viewBottomBorder.bounds
viewBottomBorder.layer.mask = gradient
A little alternative:
func setupGradient(on view: UIView, withHeight height: CGFloat) {
// this is view that holds gradient
let gradientHolderView = UIView()
gradientHolderView.backgroundColor = .clear
gradientHolderView.translatesAutoresizingMaskIntoConstraints = false
// here you set layout programmatically (you can create this view in storyoard as well and attach gradient to it)
// make sure to position this view under your text
view.addSubview(gradientHolderView) // alternative: view.insertSubview(gradientHolderView, belowSubview: YourTextLaber)
gradientHolderView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
gradientHolderView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
gradientHolderView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
gradientHolderView.heightAnchor.constraint(equalToConstant: height).isActive = true
// this is needed to kinda refresh layout a little so later we can get bounds from view. I'm not sure exactly why but without this if you create view programmatically it is needed
gradientHolderView.setNeedsLayout()
gradientHolderView.layoutIfNeeded()
// here you create gradient as layer and add it as a sublayer on your view (modify colors as you like)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = gradientHolderView.bounds
gradientLayer.colors = [UIColor.clear.cgColor, UIColor(white: 0, alpha: 0.6).cgColor]
gradientHolderView.layer.addSublayer(gradientLayer)
}
Use above code to apply Gradient to your view
var gradientBackground : CAGradientLayer?
func applyGradientToBackground() {
if self.gradientBackground != nil {
self.gradientBackground?.removeFromSuperlayer()
}
self.gradientBackground = CAGradientLayer()
self.gradientBackground?.frame = self.your_view_name.bounds
let cor1 = UIColor.black.withAlphaComponent(1).cgColor
let cor2 = UIColor.white.cgColor
let arrayColors = [cor1, cor2]
self.gradientBackground?.colors = arrayColors
self.your_view_name.layer.insertSublayer(self.gradientBackground!, at: 0)
}
I have the following extension to imageView:
extension UIImageView {
func addBlackGradientLayer(frame: CGRect){
let gradient = CAGradientLayer()
gradient.frame = frame
gradient.colors = [UIColor.clear.cgColor, UIColor.black.cgColor]
gradient.locations = [0.0, 1.0]
self.layer.addSublayer(gradient)
}}
imageView.addBlackGradientLayer(frame: imageView.frame)
on applying this to the imageView, I am having the following output. I tried setting the constraints and also, the autolayout.
Following is the output after the execution:
You need to call
imageView.addBlackGradientLayer(frame: imageView.bounds)
See: Cocoa: What's the difference between the frame and the bounds?
I try to add a CAGradient effect in a pie chart I make with Core Graphics. It turns out I am not able and certainly not understand very well how to apply it to a view that is part of a CGPath...
override func draw(_ rect: CGRect)
{
...
func arc(myRadius: CGFloat, myStartAngle: CGFloat, myEndAngle: CGFloat) {
// This is the pie chart segment
context?.setFillColor(phenotypeColor.cgColor)
context?.move(to: center)
context?.addArc(center: center, radius: finalRadius, startAngle: myStartAngle, endAngle: myEndAngle, clockwise: true)
context?.fillPath()
(...)
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.bounds
gradientLayer.colors = [UIColor.red, UIColor.blue]
self.layer.addSublayer(gradientLayer)
}
I don't see any gradient on the screen (only the white background...).
Lastly, I also tried to clip the context juste after saving its state but I am not sure I clip anything since I don't see any gradient (either on the whole view or just on the segment). I read the documentation but it does not clear things up (in my case...).
cgColor was missing... Sorry for the inconvenience.
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.bounds
gradientLayer.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
self.layer.addSublayer(gradientLayer)
I have a PageViewController and need to set a gradient background to it.
When using gradient background in normal ViewControllers, I use the following:
let layer = self.layer as! CAGradientLayer
layer.colors = [FirstColor.cgColor, SecondColor.cgColor]
layer.locations = [0.5]
when I try to use self.view.layer inside my PageViewController I get an error:
Could not cast value of type 'CALayer' (0x104f57900) to 'CAGradientLayer'
Can someone help me setting the background of a page view controller to an gradient?
Thanks
Hi you can create a UIView extension and just call like this:
view.applyGradient(colours: [UIColor.red, UIColor.green])
here the extension code
extension UIView {
func applyGradient(colours: [UIColor]) -> Void {
clipsToBounds = true
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.cgColor }
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 1, y: 0)
layer.insertSublayer(gradient, at: 0)
}
}
with this code you can apply to UIButtons, UILabels, anything that extends from UIView
hope it helps