Reputation: 59
Hi I'm trying to put a gradient background in an UIButton. This is my method but for the iPhone 7 plus or 8 plus it does not cover all the button. When a see the uibutton frame (174.5, 0.0, 164.5, 47.0) but after is load I can see that is (194.5, 0.0, 184.5, 47.0). It looks like this
func setRedGradiant(){
self.layer.shadowOffset = CGSize.zero
self.layer.shadowColor = UIColor(red:0, green:0, blue:0, alpha:0.5).cgColor
self.layer.shadowOpacity = 1
self.layer.shadowRadius = 4
let gradient = CAGradientLayer()
print(self.frame)
gradient.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
gradient.colors = [
UIColor(red:0.97, green:0.34, blue:0.39, alpha:1).cgColor,
UIColor(red:0.94, green:0.17, blue:0.2, alpha:1).cgColor
]
gradient.locations = [0, 1]
gradient.startPoint = CGPoint(x: 0.5, y: 0)
gradient.endPoint = CGPoint(x: 0.5, y: 1)
gradient.cornerRadius = self.frame.size.height / 2
self.layer.addSublayer(gradient)
}
@IBOutlet weak var signInButton: UIButton!{
didSet{
signInButton.setRedGradiant()
}
}
Upvotes: 0
Views: 323
Reputation: 1392
I guess you should call signInButton.setRedGradiant()
at viewDidLoad
, also use .bounds
instead of .frame
at function:
func setRedGradiant(){
self.layer.shadowOffset = CGSize.zero
self.layer.shadowColor = UIColor(red:0, green:0, blue:0, alpha:0.5).cgColor
self.layer.shadowOpacity = 1
self.layer.shadowRadius = 4
let gradient = CAGradientLayer()
print(self.bounds)
gradient.frame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.bounds.size.height)
gradient.colors = [
UIColor(red:0.97, green:0.34, blue:0.39, alpha:1).cgColor,
UIColor(red:0.94, green:0.17, blue:0.2, alpha:1).cgColor
]
gradient.locations = [0, 1]
gradient.startPoint = CGPoint(x: 0.5, y: 0)
gradient.endPoint = CGPoint(x: 0.5, y: 1)
gradient.cornerRadius = self.bounds.size.height / 2
self.layer.addSublayer(gradient)
}
Upvotes: 0
Reputation: 154613
The gradient's frame needs to be set after the size of the button has been established. One handy way to do that is to create a subclass of UIButton
and override layoutSubviews
to set up the gradient.
layoutSubviews()
will be called anytime the frame of the button changes, but you'll only want to set up the gradient the first time. Use a property to store the gradient so that you can update the frame
on later calls.
class GradientButton: UIButton {
var gradient: CAGradientLayer?
override func layoutSubviews() {
super.layoutSubviews()
setRedGradient()
}
func setRedGradient() {
if gradient == nil {
self.layer.shadowOffset = CGSize.zero
self.layer.shadowColor = UIColor(red:0, green:0, blue:0, alpha:0.5).cgColor
self.layer.shadowOpacity = 1
self.layer.shadowRadius = 4
self.gradient = CAGradientLayer()
self.gradient?.colors = [
UIColor(red:0.97, green:0.34, blue:0.39, alpha:1).cgColor,
UIColor(red:0.94, green:0.17, blue:0.2, alpha:1).cgColor
]
self.gradient?.locations = [0, 1]
self.gradient?.startPoint = CGPoint(x: 0.5, y: 0)
self.gradient?.endPoint = CGPoint(x: 0.5, y: 1)
self.layer.addSublayer(self.gradient!)
}
// Always update the frame, even if this isn't the first call
self.gradient?.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
self.gradient?.cornerRadius = self.frame.size.height / 2
}
}
To use this in the Storyboard, change the class
of your UIButton
to GradientButton
in the Identity Inspector.
Your outlet becomes:
@IBOutlet weak var signInButton: GradientButton!
The advantage of doing it this way is that the button sets and updates its own gradient which is nice if you have two or more buttons.
A future improvement would be to make the colors a property so that you could have more than just red buttons.
Upvotes: 1
Reputation: 2829
When your @IBOutlet
is set, view
doesn't has correct frame. I suggest you to learn more about UIViewController lifecycle
to understand this problem.
Correct solution for you will be to call setRedGradiant
for appropriate button on viewWillLayoutSubviews
method.
This method is called each time when your view bounds is changed.
Upvotes: 3