swiftbackgroundgradientnswindownsgradient

Textured NSWindow Background Gradient


I am trying to generate my own textured NSWindow so it appears with a different gradient to the default metallic appearing one.

So far I've subclassed NSWindow with no success as below.

import Cocoa

class PSWindow: NSWindow {

    override init(contentRect: NSRect, styleMask aStyle: Int, backing bufferingType: NSBackingStoreType, defer flag: Bool) {
        super.init(contentRect: contentRect, styleMask: aStyle, backing: bufferingType, defer: flag)

        let gradient: NSGradient = NSGradient(startingColor: NSColor(red: 48 / 255, green: 35 / 255, blue: 174 / 255, alpha: 1), endingColor: NSColor(red: 200 / 255, green: 109 / 255, blue: 215 / 255, alpha: 1))

        gradient.drawInRect(contentRect, angle: 45)
    }
}

Am I even going about this the correct way?


Solution

  • NSWindow is a subclass of NSResponder and you shouldn't be drawing within it.

    Solutions:

    1. You should override "contentView" variable (custom window subclass) and set its layer to CAGradientLayer which you create in the set method of "contentView"

    2. Create custom subclass of NSView and set the it to be the view of custom window in the Storyboard/XIB. In the view you either override drawInRect or use layer approach.

    Additionally look here How to draw custom NSWindow

    Quick dirty code follows

    import Cocoa
    
    class CustomWindow : NSWindow {
      override init(contentRect: NSRect, styleMask aStyle: Int, backing bufferingType: NSBackingStoreType, defer flag: Bool) {
        super.init(contentRect: contentRect, styleMask: aStyle, backing: bufferingType, defer: flag)
      }
    
      override var contentView: AnyObject {
        set {
          var view = newValue as! NSView
          view.wantsLayer = true
          let colorTop = NSColor(red: 48 / 255, green: 35 / 255, blue: 174 / 255, alpha: 1).CGColor
          let colorBottom = NSColor(red: 200 / 255, green: 109 / 255, blue: 215 / 255, alpha: 1).CGColor
          let gradient  = CAGradientLayer()
          gradient.colors = [ colorTop, colorBottom]
          gradient.locations = [ 0.0, 1.0]
          view.layer = gradient
          super.contentView = view
    
        }
        get {
          return super.contentView
        }
      }
    
      required init?(coder: NSCoder) {
          fatalError("init(coder:) has not been implemented")
      }
    
    }
    

    Window with background

    Solution 2:

    import Cocoa
    
    class CustomView : NSView {
    
      override func drawRect(dirtyRect: NSRect) {
        let colorTop = NSColor(red: 48 / 255, green: 35 / 255, blue: 174 / 255, alpha: 1)
        let colorBottom = NSColor(red: 200 / 255, green: 109 / 255, blue: 215 / 255, alpha: 1)
        let gradient = NSGradient(colors: [colorTop, colorBottom])
        gradient.drawInRect(dirtyRect, angle: 45)
      }
    }
    

    Solution2

    If you need custom titlebar then look here. It's a lot of work.

    PS: Remember that actual drawing is done in NSView