Set Background Gradient on Button in Swift

Set Background Gradient on Button in Swift

Your code works fine. You just have to remember to set the gradient's frame every time. It is better to just make the gradient category also set the frame of the view for you.

That way you don't forget and it applies fine.

import UIKit

extension UIView {

func applyGradient(colours: [UIColor]) -> CAGradientLayer {
return self.applyGradient(colours: colours, locations: nil)
}

func applyGradient(colours: [UIColor], locations: [NSNumber]?) -> CAGradientLayer {
let gradient: CAGradientLayer = CAGradientLayer()
gradient.frame = self.bounds
gradient.colors = colours.map { $0.cgColor }
gradient.locations = locations
self.layer.insertSublayer(gradient, at: 0)
return gradient
}
}

class ViewController: UIViewController {

@IBOutlet weak var btn: UIButton!

override func viewDidLoad() {
super.viewDidLoad()

self.btn.applyGradient(colours: [.yellow, .blue])
self.view.applyGradient(colours: [.yellow, .blue, .red], locations: [0.0, 0.5, 1.0])
}

}

Buttons are views. You apply gradients to it the same way you would apply it to any other view.

Picture Proof:
Sample Image

Video Proof:
https://i.imgur.com/ssDTqPu.mp4

Why is the linear gradient not fully applied to ios button

Usually, viewDidLoad for view controllers or init for custom views is too early for gradient frames. Also, their frames will most likely change later on, which you need to handle.

If you are applying a gradient to a custom view, try updating its frame inside layoutSubviews() (from this great answer).

class GradientButton: UIButton {

/// update inside layoutSubviews
override func layoutSubviews() {
super.layoutSubviews()
gradientLayer.frame = bounds
}

private lazy var gradientLayer: CAGradientLayer = {
let l = CAGradientLayer()
l.frame = self.bounds
l.colors = [UIColor.systemYellow.cgColor, UIColor.systemPink.cgColor]
l.startPoint = CGPoint(x: 0, y: 1)
l.endPoint = CGPoint(x: 0, y: )
layer.insertSublayer(l, at: 0)
return l
}()
}

For a view in a view controller, try viewDidLayoutSubviews().

class ViewController: UIViewController {

@IBOutlet weak var addToCart: UIButton!
var gradientLayer: CAGradientLayer? /// keep a reference to the gradient layer so we can update its frame later

override func viewDidLoad() {
super.viewDidLoad()

/// still first make the gradient inside viewDidLoad
applyGradient(colors: [UIColor.systemYellow.cgColor, UIColor.systemPink.cgColor])
}

override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

/// update here!
self.gradientLayer?.frame = self.addToCart.bounds
}

private func applyGradient(colors: [CGColor]) {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = colors
gradientLayer.startPoint = CGPoint(x: 0, y: 1)
gradientLayer.endPoint = CGPoint(x: 0, y: 0)
gradientLayer.frame = self.addToCart.bounds
self.addToCart.layer.insertSublayer(gradientLayer, at: 0)

self.gradientLayer = gradientLayer
}
}

How to put a gradient in a background button witch contains a system image?

Actually, the button image goes behind the layer. Try this:

extension UIButton {
func applyGradient(colors: [CGColor], radius: CGFloat = 0, startGradient: CGPoint = .init(x: 0.5, y: 0), endGradient: CGPoint = .init(x: 0.5, y: 1)) {
// check first if there is already a gradient layer to avoid adding more than one
let gradientLayer = CAGradientLayer()
gradientLayer.cornerRadius = radius
gradientLayer.colors = colors
gradientLayer.startPoint = startGradient
gradientLayer.endPoint = endGradient
gradientLayer.frame = bounds
layer.insertSublayer(gradientLayer, at: 0)
}
}

And in the viewDidLoad put:

ampouleButton.applyGradient(colors: [Theme.bleu!.cgColor, Theme.softBlue!.cgColor], radius: self.ampouleButton.frame.height / 2, startGradient: CGPoint(x: 0, y: 0.5), endGradient: CGPoint(x: 1, y: 0)) 
if let imgView = ampouleButton.imageView { ampouleButton.bringSubviewToFront(imgView) }

Find applyGradient function from here : https://stackoverflow.com/a/62093932/2303865

How do you give a UIButton a gradient and give that button a bottom shadow with that same gradient in SwiftUI?

You can do it like this:

Button(action: createTask) {
Text(“MyButton“)
.color(.white)
.font(Font.system(size: 17))
.frame(height: 56)
.frame(minWidth: 0, maxWidth: .infinity)
.background(LinearGradient.actionButton, cornerRadius: 28)
.shadow() // configure shadow as you want
}

And just to improve code's readable I've created gradient separately:

fileprivate extension LinearGradient {
static let actionButton = LinearGradient(gradient: Gradient(colors: [Color(“ActionGradientFirst”), Color(“ActionGradientSecond”)]),
startPoint: .topLeading,
endPoint: .bottomTrailing)
}

Colors ActionGradientFirst and ActionGradientSecond I declared in Assets.xcasset

Gradient color as a Background color of UIButton in Swift4

Try this and see:

@IBOutlet weak var loginButton: UIButton!
func testGradientButton() -> Void {
let gradientColor = CAGradientLayer()
gradientColor.frame = loginButton.frame
gradientColor.colors = [UIColor.blue.cgColor,UIColor.red.withAlphaComponent(1).cgColor]
self.loginButton.layer.insertSublayer(gradientColor, at: 0)
}

Here is result:

Sample Image

Also note: Values for RGB colors in your code, are much higher than its normal value. See your console log, it might printed following error:

[Graphics] UIColor created with component values far outside the expected range. Set a breakpoint on UIColorBreakForOutOfRangeColorComponents to debug. This message will only be logged once.

Divide all values with 255.0 and use insertSubLayer function.

let color1 = UIColor(red: 183.0/255.0, green: 46.0/255.0, blue: 79.0/255.0, alpha: 1)
let color2 = UIColor(red: 232.0/255.0, green: 79.0/255.0, blue: 80.0/255.0, alpha: 1)
let color3 = UIColor(red: 145.0/255.0, green: 21.0/255.0, blue: 79.0/255.0, alpha: 1)

Here is result with your color code values:

func testGradientButton() -> Void {
let gradientColor = CAGradientLayer()
gradientColor.frame = loginButton.frame
let color1 = UIColor(red: 183.0/255.0, green: 46.0/255.0, blue: 79.0/255.0, alpha: 1)
let color2 = UIColor(red: 232.0/255.0, green: 79.0/255.0, blue: 80.0/255.0, alpha: 1)
let color3 = UIColor(red: 145.0/255.0, green: 21.0/255.0, blue: 79.0/255.0, alpha: 1)
gradientColor.colors = [color1.cgColor,color2.cgColor,color3.cgColor]
self.loginButton.layer.insertSublayer(gradientColor, at: 0)
}

Sample Image

Gradient Button Crashed when Removing Gradient

You can give your CALayer a name this way you can find the index of your layer before removing it:

extension UIButton {
func applyGradient(colors: [CGColor], radius: CGFloat = 0, startGradient: CGPoint = .init(x: 0.5, y: 0), endGradient: CGPoint = .init(x: 0.5, y: 1)) {
// check first if there is already a gradient layer to avoid adding more than one
if let gradientLayer = layer.sublayers?.first(where: {$0.name == "gradient" }) as? CAGradientLayer {
gradientLayer.cornerRadius = radius
gradientLayer.colors = colors
gradientLayer.startPoint = startGradient
gradientLayer.endPoint = endGradient
gradientLayer.frame = bounds
// if not found create a new gradient layer
} else {
let gradientLayer = CAGradientLayer()
gradientLayer.name = "gradient"
gradientLayer.cornerRadius = radius
gradientLayer.colors = colors
gradientLayer.startPoint = startGradient
gradientLayer.endPoint = endGradient
gradientLayer.frame = bounds
layer.insertSublayer(gradientLayer, at: 0)
}
}
}

@IBAction func button(_ sender: UIButton) {
sender.setTitleColor(.systemBackground, for: .selected)
sender.isSelected.toggle()
if sender.isSelected {
sender.layer.borderWidth = 0
sender.applyGradient(colors: [ #colorLiteral(red: 0.5098039216, green: 0.8431372549, blue: 0.5254901961, alpha: 1) , #colorLiteral(red: 0.3058823529, green: 0.6941176471, blue: 0.3215686275, alpha: 1) ], radius: 10)
} else {
sender.layer.borderWidth = 1
if let firstIndex = sender.layer.sublayers?.firstIndex(where: {$0.name == "gradient" }) {
sender.layer.sublayers?.remove(at: firstIndex)
}
}
}


Related Topics



Leave a reply



Submit