Although you are didn't share the issue code, Seems like you have issues with the layer! CALayer
is Not auto-resizing due to frame changes, so it sets by the initial setup and stays the same. So first try to make it more like a view. The following code gives you a customizable gradient view that is reacting to any layout call (even right in the Storyboard!):
@IBDesignable
final class GradientView: UIView {
@IBInspectable var firstColor: UIColor = .clear { didSet { updateView() } }
@IBInspectable var secondColor: UIColor = .clear { didSet { updateView() } }
@IBInspectable var startPoint: CGPoint = CGPoint(x: 0, y: 0) { didSet { updateView() } }
@IBInspectable var endPoint: CGPoint = CGPoint(x: 1, y: 1) { didSet { updateView() } }
override class var layerClass: AnyClass { get { CAGradientLayer.self } }
override func layoutSubviews() {
super.layoutSubviews()
updateView()
layer.frame = bounds
}
private func updateView() {
let layer = self.layer as! CAGradientLayer
layer.colors = [firstColor, secondColor].map {$0.cgColor}
layer.startPoint = startPoint
layer.endPoint = endPoint
}
}

Then you can add it to your custom view and frame it to the parent (or any other layout method that you like):
class CustomButton: UIButton{
override init(frame: CGRect) {
super.init(frame: frame)
setupButton()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupButton()
}
private lazy var gradientView: GradientView = {
// Setup the gradient here
let gradient = GradientView(frame: frame)
gradient.startPoint = .init(x: 0, y: 0)
gradient.endPoint = .init(x: 1, y: 1)
gradient.firstColor = .red
gradient.secondColor = .orange
return gradient
}()
private func addLayerIfNeeded() {
guard gradientView.superview == nil else { return }
addSubview(gradientView)
}
override func layoutSubviews() {
super.layoutSubviews()
gradientView.frame = bounds
}
func setupButton() {
addLayerIfNeeded()
setTitleColor(.white, for: .normal)
}
}
