This post walks through the implementation for GradientButton, an NSButton subclass. GradientButton is a button with text on top of a gradient background.

  1. Configure Properties
  2. Override draw(:)
  3. Draw Gradient
  4. Complete Implementation

Configure Properties

To draw a gradient using NSGradient, specify at minimum the colors of the gradient and the gradient draw angle. For GradientButton, the colors and angle are implemented as configurable properties:

@IBDesignable class GradientButton: NSButton {
    @IBInspectable var gradientInitialColor: NSColor = .white
    @IBInspectable var gradientFinalColor: NSColor = .black
    @IBInspectable var gradientAngle: CGFloat = 270.0
}

Override draw(:)

Prepare to add custom draw code by overriding draw(:):

    // inside of GradientButton
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
    }
    
    // ...

Draw Gradient

Use NSGradient to draw the gradient. In order to make the button interactive, the gradient angle is changing when the button is in the highlighted state. In other words, the gradient will change when the user clicks on the button.

    // inside of draw(_ dirtyRect:)

    // Configure the gradient
    var gradientAngle = self.gradientAngle
    if isHighlighted { gradientAngle += 45 }
        
    let gradient = NSGradient(colors: [
        gradientInitialColor, gradientFinalColor
    ])
        
    // Draw the gradient
    gradient?.draw(in: bounds, angle: gradientAngle)

    // ...

NSButton With A Gradient Background

That's it! With GradientButton you can implement an NSButton with a gradient background. The provided implementation of GradientButton results in the following:

Interactive NSButton with a gradient background
Interactive NSButton with a gradient background

Complete Implementation

@IBDesignable class GradientButton: NSButton {
    @IBInspectable var gradientInitialColor: NSColor = .white
    @IBInspectable var gradientFinalColor: NSColor = .black
    @IBInspectable var gradientAngle: CGFloat = 270.0
    
    override func draw(_ dirtyRect: NSRect) {
        // Configure the gradient
        var gradientAngle = self.gradientAngle
        if isHighlighted { gradientAngle += 45 }
        
        let gradient = NSGradient(colors: [
            gradientInitialColor, gradientFinalColor
        ])
        
        // Draw the gradient
        gradient?.draw(in: bounds, angle: gradientAngle)
        
        super.draw(dirtyRect)
    }
}