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.
Asked
Active
Viewed 352 times
1
-
Have you looked at this answer? https://stackoverflow.com/a/36836787 – Hima Nov 02 '19 at 04:35
2 Answers
3
You can make your own BorderedButton
subclass that will:
- Add gradient sublayer;
- Create shape layer consisting of the path of the border; And
- Use that shape layer as mask to the gradient layer to yield gradient border in the shape of the path.
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:
- I update the
frame
of the gradient layer and the path that is used as themask
inside thelayoutSubviews
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). - I’ve made this
@IBDesignable
so that you can even add this to a storyboard and you’ll see it rendered correctly. - I’ve made the
cornerRadius
andlineWidth
to be@IBInspectable
so that you can adjust these in IB (and because they havedidSet
observers that sets “needs layout”, they’ll ensure that changes are observable in the storyboard).
Anyway, that yields:

Rob
- 415,655
- 72
- 787
- 1,044
-1
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)
}

Swati
- 1,417
- 1
- 15
- 35