Applying Gradient on UIView not getting expected result - ios

I just simply want to apply Gradient with 2 UIColors that's why I written below code.
class Constants: NSObject {
class func applyGradient(localView:UIView, color1:UIColor, color2:UIColor) {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = localView.bounds
gradient.colors = [color1.CGColor, color2.CGColor]
gradient.startPoint = CGPoint(x: 0,y: 0)
gradient.endPoint = CGPoint(x: 0,y: 1)
localView.layer.insertSublayer(gradient, atIndex: 0)
localView.layer.masksToBounds = true
}
}
and applying via below code in UIViewController's viewDidLoad.
Constants.applyGradient(viewContactDetail, color1: gradientColor1, color2: gradientColor2)
Constants.applyGradient(viewDiscountDetail, color1: gradientColor1, color2: gradientColor2)
Constants.applyGradient(viewTermsCondDetail, color1: gradientColor1, color2: gradientColor2)
Constants.applyGradient(viewDiscountAvailDetail, color1: gradientColor1, color2: gradientColor2)
And here is the result what I'm getting
You can see, Gradient isn't apply on specific view properly.
I'm not getting what is wrong with my code.
EDIT:
Here is the hierarchical view.

Try this....hope its helpful for you
let gradientLayer = CAGradientLayer()
gradientLayer.frame = self.shadowview.bounds
let colorTop = UIColor.green.cgColor
let colorBottom = UIColor.black.cgColor
gradientLayer.colors = [colorTop, colorBottom]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.0)
gradientLayer.endPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.locations = [ 0.0, 1.0]
self.shadowview.layer.addSublayer(gradientLayer)

You can try this simple code too in which you can give frame of gradient layer and give color too
let gradient1 = CAGradientLayer()
gradient1.frame = CGRect(origin: CGPointZero, size: CGSize (width: self.view.frame.size.width,height: btn_cancel.frame.size.height))
gradient1.colors = [UIColor.whiteColor().CGColor, UIColor.init(red: 237.0/255.0, green: 237.0/255.0, blue: 237.0/255.0, alpha: 1.0).CGColor]
print(gradient1.frame)
just Add that layer to the view
"YOUR VIEW".layer.addSublayer(gradient1)
In Image You can see I added gradient layer to button, So you can do as same to add in your view or any other control

Calling layoutIfNeeded() before setting the frame worked for me. If in your case if don't want to call this try using willDisplayCell by setting a bool which will be applied for the first time only and when your frames are ready.

Related

I am trying to add gradient as a sublayer in view but its not resizing it equal to the view

let cellview: UIView!
let gradient = CAGradientLayer()
let topColor = UIColor(red: 0.435, green: 0, blue: 0.635, alpha: 1.0)
let bottomColor = UIColor(red: 0.255 , green: 0.043, blue: 0.373, alpha: 1.0)
gradient.colors = [topColor.cgColor, bottomColor.cgColor]
gradient.startPoint = CGPoint(x:0, y:0)
gradient.endPoint = CGPoint(x:0.3, y:1)
cellview = UIView(frame: CGRect(x: 0, y: 0, width: 192, height: 160))
gradient.frame = cellview.bounds
gradient.masksToBounds = true
cellview.layer.addSublayer(gradient)
I wrote the above code according to the code gradient should cover entire view. But this is how the gradient appearing.
Following is the screen shot for app
Here's a function i use to create gradients, you may find it useful
func createGradientBackground(gradientColor: UIColor, darkStylePreferred: Bool, viewToUse: UIView) {
let gradient = CAGradientLayer(layer: viewToUse.layer)
gradient.frame = viewToUse.bounds
gradient.locations = [0, 1]
viewToUse.layer.insertSublayer(gradient, at: 0)
let animation = CABasicAnimation(keyPath: "locations")
animation.toValue = [0, 0.11, 1]
animation.fromValue = [0, 0.9, 1]
if darkStylePreferred {
gradient.colors = [UIColor.black.cgColor, gradientColor.cgColor, UIColor.black.cgColor]
} else {
gradient.colors = [UIColor.white.cgColor, gradientColor.cgColor, UIColor.white.cgColor]
}
animation.autoreverses = true
animation.repeatCount = Float.infinity
animation.speed = 0.015
animation.isRemovedOnCompletion = false
gradient.add(animation, forKey: nil)
}
I figured it out, just answering my self so it might help someone later on.
All I had to do is set the gradient in func viewDidLayoutSubviews(). And this solved my issue

UIView with gradient not changing colors when button is tapped

When a user clicks on a button, it randomizes the colors used to create a gradient in a large circle. Beneath it are two small circles that display the solid colors used for the gradient. They all display correctly at the start (main circle is a gradient of the randomized smaller circles' color) but when I click on the button, only the smaller circles change color; the large circle stays at the same gradient colors.
Extensions and View Controller:
extension UIView {
func setupGradientBackground(colorOne: UIColor, colorTwo: UIColor) {
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = [colorOne.cgColor, colorTwo.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
gradientLayer.frame = self.bounds
self.layer.insertSublayer(gradientLayer, at: 0)
}
}
extension UIColor {
static var random: UIColor {
return UIColor(red: .random(in: 0...1), green: .random(in: 0...1), blue: .random(in: 0...1), alpha: 1.0)
}
}
class GradientController: UIViewController {
let gradientView = GradientView()
let leftGradientColor: UIColor = .random
let rightGradientColor: UIColor = .random
}
override func viewDidLoad() {
super.viewDidLoad()
view = gradientView
newGradient()
}
func newGradient() {
gradientView.mainCircleView.setupGradientBackground(colorOne: leftGradientColor, colorTwo: rightGradientColor)
gradientView.colorCircleLeftView.backgroundColor = leftGradientColor
gradientView.colorCircleRightView.backgroundColor = rightGradientColor
gradientView.gradientGenerateButton.addTarget(self, action: #selector(randomGradient(sender:)), for: .touchUpInside)
}
#objc func randomGradient(sender: UIButton)
{
let leftGradient = UIColor.random
let rightGradient = UIColor.random
gradientView.colorCircleLeftView.backgroundColor = leftGradient
gradientView.colorCircleRightView.backgroundColor = rightGradient
//Here is where it's not changing colors. Doesn't seem like the VC recognizes it in this function
gradientView.mainCircleView.setupGradientBackground(colorOne: leftGradient, colorTwo: rightGradient)
}
View:
class GradientView: UIView {
//circle's UIView code in Extensions
let mainCircleView = UIView().circleView(width: 380, height: 380)
let colorCircleLeftView = UIView().circleView(width: 40, height: 40)
let colorCircleRightView = UIView().circleView(width: 40, height: 40)
...
func setupLayout() {
...
}
}
What I've tried is changing the mainCircleView color to solid UIColors, like gradientView.mainCircleView.setupGradientBackground(colorOne: .red, colorTwo: .orange) to see if the main Circle changes to those colors in both func newGradient() and #objc func randomGradient(sender: UIButton). It only changes in func newGradient() what I've set manually, so that means the VC isn't recognizing the main Circle in the #objc func but I'm lost on how to fix it...
Any help is appreciated!
What it looks like when I click the "Generate" button (large circle should be showing brown and purple):
Update your function with this, You have to remove old layer and then insert new Sublayer.
Solution 1 :
func setupGradientBackground(colorOne: UIColor, colorTwo: UIColor) {
if let gradientLayer = (self.layer.sublayers?.compactMap { $0 as? CAGradientLayer })?.first {
gradientLayer.removeFromSuperlayer()
}
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = [colorOne.cgColor, colorTwo.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
gradientLayer.frame = self.bounds
self.layer.insertSublayer(gradientLayer, at: 0)
}
Solution 2 :
func setupGradientBackground(colorOne: UIColor, colorTwo: UIColor) {
let gradientLayer = layer.sublayers?.first as? CAGradientLayer ?? CAGradientLayer()
gradientLayer.colors = [colorOne.cgColor, colorTwo.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
gradientLayer.frame = self.bounds
guard gradientLayer.superlayer != self else {
return
}
layer.insertSublayer(gradientLayer, at: 0)
}
Solution 3 :
you can set name to your CAGradientLayer, This will help you for removing that particular layer.
func setupGradientBackground(colorOne: UIColor, colorTwo: UIColor) {
for layer in layer.sublayers ?? [] {
if layer.name == "GradientLayer" {
layer.removeFromSuperlayer()
}
}
let gradientLayer: CAGradientLayer = CAGradientLayer()
gradientLayer.colors = [colorOne.cgColor, colorTwo.cgColor]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 1.0)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.0)
gradientLayer.name = "GradientLayer"
gradientLayer.frame = self.bounds
self.layer.insertSublayer(gradientLayer, at: 0)
}
The gradient does not change because you add a new gradient below the existing one
extension UIView {
func setupGradientBackground(colorOne: UIColor, colorTwo: UIColor) {
let gradientLayer: CAGradientLayer = CAGradientLayer()
...
// ⬇ There is a mistake.
self.layer.insertSublayer(gradientLayer, at: 0)
}
}
You should change the current gradient with this new one. Or insert a new one above the old one.
Changing the gradient layer colors after setting it
extension CALayer {
func updateGradientColors(_ colors:CGColor...) {
if let layer = sublayers?.first as? CAGradientLayer {
let frame = CGRect(origin: self.bounds.origin, size: CGSize(width: self.bounds.size.width, height: self.bounds.size.height))
layer.frame = frame
layer.colors = colors
}
}
}

Creating a clear button with gradient border and gradient text

I'm trying to add a gradient to my UIButton Title and to the border of the button. I've gone through most of the solution on here which I cannot get working for the life of me, might be outdated, I'm not sure. So currently I extend the UIView in order to set the gradient of whatever. So how would I add another function for this feature?
func setGradientBackground(colorOne: UIColor, colorTwo: UIColor) {
let gradientlayer = CAGradientLayer()
gradientlayer.frame = bounds
gradientlayer.colors = [colorOne.cgColor, colorTwo.cgColor]
gradientlayer.locations = [0, 1]
gradientlayer.startPoint = CGPoint(x: 1.0, y: 0.0)
gradientlayer.endPoint = CGPoint(x: 0.0, y: 0.0)
layer.insertSublayer(gradientlayer, at: 0)
}
I have created a demo for you, you can do this with the help of CAGradientLayer see the following output and code for this.
Storyboard:
For gradient button text color and border put your UIButton inside UIView, then assign CAGradientLayer to UIview.
Note:- Don't forget to set the button as the views mask, See the following code.
import UIKit
class ViewController: UIViewController {
#IBOutlet var viewForButton: UIView!
#IBOutlet var myButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// Create a gradient layer
let gradient = CAGradientLayer()
// gradient colors in order which they will visually appear
gradient.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]
// Gradient from left to right
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
// set the gradient layer to the same size as the view
gradient.frame = viewForButton.bounds
// add the gradient layer to the views layer for rendering
viewForButton.layer.insertSublayer(gradient, at: 0)
// Tha magic! Set the button as the views mask
viewForButton.mask = myButton
//Set corner Radius and border Width of button
myButton.layer.cornerRadius = myButton.frame.size.height / 2
myButton.layer.borderWidth = 5.0
}
}
Extension: You can also prefer this extension for the same.
extension UIView{
func gradientButton(_ buttonText:String, startColor:UIColor, endColor:UIColor) {
let button:UIButton = UIButton(frame: self.bounds)
button.setTitle(buttonText, for: .normal)
let gradient = CAGradientLayer()
gradient.colors = [startColor.cgColor, endColor.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
gradient.frame = self.bounds
self.layer.insertSublayer(gradient, at: 0)
self.mask = button
button.layer.cornerRadius = button.frame.size.height / 2
button.layer.borderWidth = 5.0
}
}
How to use:
testView.gradientButton("Hello", startColor: .red, endColor: .blue)
You just need to add below UIView extension and call the function to get desire gradient button,
func covertToGradientButtonWith(title: String, radius: CGFloat, borderWidth: CGFloat, gradientStartColor: UIColor, gradientEndColor: UIColor) {
let button:UIButton = UIButton(frame: self.bounds)
button.setTitle(title, for: .normal)
let gradient = CAGradientLayer()
gradient.colors = [gradientStartColor.cgColor, gradientEndColor.cgColor]
gradient.startPoint = CGPoint(x: 0.0, y: 0.5)
gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
gradient.frame = self.bounds
self.layer.insertSublayer(gradient, at: 0)
self.mask = button
button.layer.cornerRadius = radius
button.layer.borderWidth = borderWidth
}
Hope, this solution may help you.

How to set gradient colour to UIButton in background?

Am trying to set CAGradientLayer for UIButton.
But it is not getting exactly. am I doing any wrong ?
am getting output like
You can see there is some horizontal line
Here is the code which I tried
let topColor = UIColor(red: 0.62, green: 0.38, blue: 1, alpha: 1).cgColor
let bottomColor = UIColor(red: 0.87, green: 0.51, blue: 0.93, alpha: 1).cgColor
let gradientLayer = CAGradientLayer()
gradientLayer.frame = myButton.bounds
gradientLayer.colors = [topColor, bottomColor]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
myButton.layer.insertSublayer(myButton, at: 0)
Create a Designable custom class like this
import Foundation
import UIKit
#IBDesignable class CustomButton:UIButton {
#IBInspectable var firstColor:UIColor = UIColor.clear {
didSet {
updateUI()
}
}
#IBInspectable var secondColor:UIColor = UIColor.clear {
didSet{
updateUI()
}
}
override class var layerClass: AnyClass {
get {
return CAGradientLayer.self
}
}
func updateUI(){
let gradient: CAGradientLayer = self.layer as! CAGradientLayer
gradient.frame = self.bounds
gradient.colors = [firstColor,secondColor].map { $0.cgColor }
gradient.locations = [0.0,1.0]
gradient.startPoint = CGPoint(x: 0.0, y: 1.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
}
}
from your Identity inspector set your UIbutton class to CustomButtom like this
from your Attribute inspector change your gradient color to whatever you want to set
and finally your button will be like this
if you want to change the starting and endpoint to those colors
just play around with these two values
gradient.startPoint = CGPoint(x: 0.0, y: 1.0)
gradient.endPoint = CGPoint(x: 1.0, y: 1.0)
You have to update the gradient's frame when the view is laid out:
override func viewDidLayoutSubviews() {
myButton.layer.sublayers?.first?.frame = myButton.bounds
}

Gradiant in playground different from simulator

I tried to make a gradiant using playground then make it into a subclass of uiview to use it in my codebase.
The playground code is like this:
let view = UIView(frame: CGRect(x: 0, y: 0, width: 640, height: 41
))
let gradient: CAGradientLayer = CAGradientLayer(layer: view.layer)
gradient.frame = view.frame
let lightColor = UIColor(red: 157/256, green: 157/256, blue: 154/256, alpha: 1)
let darkColor = UIColor(red: 108/256, green: 104/256, blue: 104/256, alpha: 1)
gradient.colors = [lightColor.CGColor, darkColor.CGColor]
gradient.locations = [0.6 , 0.4]
gradient.startPoint = CGPoint(x: 1, y: 0.55)
gradient.endPoint = CGPoint(x: 0, y: 0.45)
view.layer.insertSublayer(gradient, atIndex: 0)
view //displayed
And display like this:
I tried to make it into my codebase with:
class GradiantView : UIView {
override var frame: CGRect {
didSet {
let gradient: CAGradientLayer = CAGradientLayer(layer: layer)
gradient.frame = bounds
let lightColor = UIColor(red: 157/256, green: 157/256, blue: 154/256, alpha: 1)
let darkColor = UIColor(red: 108/256, green: 104/256, blue: 104/256, alpha: 1)
gradient.colors = [lightColor.CGColor, darkColor.CGColor]
gradient.locations = [0.6 , 0.4]
gradient.startPoint = CGPoint(x: 1, y: 0.55)
gradient.endPoint = CGPoint(x: 0, y: 0.45)
layer.insertSublayer(gradient, atIndex: 0)
}
}
}
However, the result is like this: (no gradiant applied)
What happened and how to fix it ?
I inverted the locations and it seems to work.
I welcome any explanation on the difference between simulator and playground.
gradientLayer.locations = [0.4 , 0.6]

Resources