I have a custom button with some shadow effect, following class i am using to create a custom button which i got from stackoverflow. It users CAShapeLayer to give effect of shadow on button.
import UIKit
class CustomButton: UIButton {
var shadowLayer: CAShapeLayer!
override func layoutSubviews() {
super.layoutSubviews()
if shadowLayer == nil {
shadowLayer = CAShapeLayer()
shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 12).cgPath
shadowLayer.fillColor = UIColor.white.cgColor
shadowLayer.shadowColor = UIColor.darkGray.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowOffset = CGSize(width: 2.0, height: 2.0)
shadowLayer.shadowOpacity = 0.8
shadowLayer.shadowRadius = 2
layer.insertSublayer(shadowLayer, at: 0)
//layer.insertSublayer(shadowLayer, below: nil) // also works
}
}
}
Following is an image of screen where i have created 4 buttons using this CustomButton Class which works fine.
when any button from above four is clicked i changed it's following property so it can look like an active button.
// to make button active
func setSelectedButton(sender:CustomButton){
//sender.backgroundColor = UIColor.red
sender.shadowLayer.fillColor = UIColor(named: "headerColor")?.cgColor
sender.setTitleColor(UIColor.white, for: .normal)
}
// to make button inactive
func setUnselected(sender:CustomButton){
//sender.backgroundColor = UIColor.init(red: 80/255, green:101/255, blue: 161/255, alpha: 1)
sender.shadowLayer.fillColor = UIColor.white.cgColor
sender.setTitleColor(.black, for: .normal)
}
Everything works fine. Now what i want is whenever view appears i want the first button to be selected by default which is routineButton to do that i have written following code in viewWillAppearMethod
override func viewWillAppear(_ animated: Bool) {
self.navigationItem.title = navigationTitle
self.view.makeToastActivity(.center)
self.routineButton.sendActions(for: .touchUpInside) //default selection of routineButton
loadEvaluationList(userId: 8, evaluationType: "RT") {
self.view.hideToastActivity()
}
}
when self.routineButton.sendActions(for: .touchUpInside)
executes it call setSelectedButton(sender:CustomButton)
method which gives error at following line
sender.shadowLayer.fillColor = UIColor(named: "headerColor")?.cgColor
which says shadowLayer is nil. This problem occur only when i try to set default selected button on viewWillAppear Method otherwise it works perfact. I think the problem occur because shadowLayer property of CustomButton is not initialised at time of viewWillAppear. so anyone knows what should i do? it will be helpful. Thank you in advance.
Move the initialization code for shadowLayer
in the init methods, something like this:
import UIKit
class CustomButton: UIButton {
var shadowLayer: CAShapeLayer!
override init(frame: CGRect) {
super.init(frame: frame)
self.initShadowLayer()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.initShadowLayer()
}
func initShadowLayer() {
if shadowLayer == nil {
shadowLayer = CAShapeLayer()
shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 12).cgPath
shadowLayer.fillColor = UIColor.white.cgColor
shadowLayer.shadowColor = UIColor.darkGray.cgColor
shadowLayer.shadowPath = shadowLayer.path
shadowLayer.shadowOffset = CGSize(width: 2.0, height: 2.0)
shadowLayer.shadowOpacity = 0.8
shadowLayer.shadowRadius = 2
layer.insertSublayer(shadowLayer, at: 0)
}
}
override func layoutSubviews() {
super.layoutSubviews()
// Reset the path because bounds could have been changed
shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: 12).cgPath
shadowLayer.shadowPath = shadowLayer.path
}
}
viewWillAppear
is called before layoutSubviews
of the button and shadowLayer
is not initialized yet. Also try not to call sendActions(for: .touchUpInside)
, instead call the setSelectedButton
function if you just want to configure the button appearance.