Reputation: 6253
I have read others questions and answers, but without find a valid answer for me.
I'm using this code to add a gradient into UIButton using the layer:
let gradient = CAGradientLayer()
gradient.colors = [UIColor.black.cgColor, UIColor.gray.cgColor]
gradient.locations = [0.0, 1.0]
myButton.setNeedsLayout() //I added this line then change next line to frame
gradient.frame = myButton.frame //I tried bounds
myButton.layer.insertSublayer(gradient, at: 0)
The button is showed some times with the gradient out the frame button. And if I apply the same code but to a UITabbar instead of a button appears the similar problem, gradient ins't applied to all frame... What could be the problem? And the solution?
Y can't load the gradient from layoutSubviews by the application's architecture.
Upvotes: 0
Views: 220
Reputation: 149
I am using this custom button style to set gradient.
import UIKit
class CustomButton: UIButton {
init() {
super.init(frame: .zero)
customInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
customInit()
}
private func customInit() {
setupGradient()
}
private func setupGradient() {
let gradient = CAGradientLayer()
gradient.name = "gradient"
gradient.frame = self.bounds
gradient.cornerRadius = self.layer.cornerRadius
gradient.colors = [
UIColor(red: 1.00, green: 0.41, blue: 0.35, alpha: 1.0).cgColor,
UIColor(red: 1.00, green: 0.00, blue: 0.67, alpha: 1.0).cgColor
]
gradient.locations = [0, 1]
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 1, y: 1)
self.layer.insertSublayer(gradient, at: 0) // insert to the back
}
}
Upvotes: 0
Reputation: 639
To resolve your problem, you could normally change the following line of your code,
gradient.frame = myButton.frame
to
gradient.frame = myButton.bounds
The reason you were facing the issue is that when you use the .frame
property of the view/button, it provides the origin of the view/button with respect to its superview, which can be anything.
When you use the .bounds
property, the origin is based on its own view space which will give a (0,0) point as origin most of the time. But not always, which brings me to the following consensus,
The solution might still run into issues when working with auto layouts, since the layout engine can change the size of the button after the gradient has been applied.
An elegant solution is to have a custom button class which is to be applied to all the buttons which have a gradient applied to it. This class should resize the gradient when the view updates the layouts.
class GradientButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
updateGradientLayers()
}
private func updateGradientLayers() {
guard let sublayers = layer.sublayers else { return }
for layer in sublayers {
if let gradientView = layer as? CAGradientLayer {
gradientView.frame = bounds
}
}
}
}
Upvotes: 1