I want to achieve something like this. I have searched for this. I get suggestions that I can put a gradient view behind the button with height and width more than the button. But I want exact corner radius and border color with gradients.

I want to achieve something like this. I have searched for this. I get suggestions that I can put a gradient view behind the button with height and width more than the button. But I want exact corner radius and border color with gradients.

You can make your own BorderedButton subclass that will:
E.g.:
@IBDesignable
class BorderedButton: UIButton {
@IBInspectable var lineWidth: CGFloat = 3 { didSet { setNeedsLayout() } }
@IBInspectable var cornerRadius: CGFloat = 10 { didSet { setNeedsLayout() } }
let borderLayer: CAGradientLayer = {
let borderLayer = CAGradientLayer()
borderLayer.type = .axial
borderLayer.colors = [#colorLiteral(red: 0.6135130525, green: 0.3031745553, blue: 0.9506058097, alpha: 1).cgColor, #colorLiteral(red: 0.9306473136, green: 0.1160953864, blue: 0.8244602084, alpha: 1).cgColor]
borderLayer.startPoint = CGPoint(x: 0, y: 1)
borderLayer.endPoint = CGPoint(x: 1, y: 0)
return borderLayer
}()
override init(frame: CGRect = .zero) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
configure()
}
override func layoutSubviews() {
super.layoutSubviews()
borderLayer.frame = bounds
let mask = CAShapeLayer()
let rect = bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2)
mask.path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).cgPath
mask.lineWidth = lineWidth
mask.fillColor = UIColor.clear.cgColor
mask.strokeColor = UIColor.white.cgColor
borderLayer.mask = mask
}
}
private extension BorderedButton {
func configure() {
layer.addSublayer(borderLayer)
}
}
Note that:
frame of the gradient layer and the path that is used as the mask inside the layoutSubviews method, which ensures that the border is correctly rendered if the size changes (e.g. you’re using constraints to define the size of the view).@IBDesignable so that you can even add this to a storyboard and you’ll see it rendered correctly.cornerRadius and lineWidth to be @IBInspectable so that you can adjust these in IB (and because they have didSet observers that sets “needs layout”, they’ll ensure that changes are observable in the storyboard).Anyway, that yields:
extension CALayer {
func addGradienBorder(colors:[UIColor],width:CGFloat = 1) {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = CGRect(origin: CGPointZero, size: self.bounds.size)
gradientLayer.startPoint = CGPointMake(0.0, 0.5)
gradientLayer.endPoint = CGPointMake(1.0, 0.5)
gradientLayer.colors = colors.map({$0.CGColor})
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = width
shapeLayer.path = UIBezierPath(rect: self.bounds).CGPath
shapeLayer.fillColor = nil
shapeLayer.strokeColor = UIColor.blackColor().CGColor
gradientLayer.mask = shapeLayer
self.addSublayer(gradientLayer)
}