Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set color of NSView in Cocoa App using Swift?

I used to develop for iOS and I do not understand why I can't easily change background color of NSViews inside my main view.

Let's say I have a view controller with a main view in it. In this view I've added 3 custom views, I've set their constraints to fit the main view.

I've created 3 outlets to my view controller:

@IBOutlet weak var topView: NSView!
@IBOutlet weak var leftView: NSView!
@IBOutlet weak var rightView: NSView!

3 views in IB

After that, I'm trying to set the background of these views and can't do this. I don't see any color changes when I run the app.

Here is the code I've added to show colors for my custom views:

override func viewDidLoad() {
        super.viewDidLoad()

        self.view.wantsLayer = true

        self.topView.layer?.backgroundColor = NSColor.blue.cgColor
        self.rightView.layer?.backgroundColor = NSColor.green.cgColor
        self.leftView.layer?.backgroundColor = NSColor.yellow.cgColor
    }

And it shows nothing (no background color on my views):

no background color on views

I can't understand why this code doesn't work. Why it is so hard to set the color of an NSView (while it is so easy in iOS development)? I'm using Xcode 8 and writing code using Swift 3.

like image 247
Adelmaer Avatar asked Sep 07 '17 10:09

Adelmaer


2 Answers

You should set wantsLayer to true for your subviews, not for your superview.

self.topView.wantsLayer = true
self.rightView.wantsLayer = true
self.leftView.wantsLayer = true
like image 181
Tamás Sengel Avatar answered Nov 04 '22 05:11

Tamás Sengel


The layer approach is convenient, but it will create a terrible issue unless you have a very dark background again a bright text color (or vice versa... I don't remember which is which any more.) for an NSTextField label. Unlike Cocoa Touch, which lets you change the background color of a UIView object, unfortunately, you have to subclass NSView in Cocoa for certainty like the following.

import Cocoa

class RedView: NSView {
    override func draw(_ rect: NSRect) {
        super.draw(rect)

        let color = NSColor.red
        color.set()
        NSRectFill(rect)
    }
}

Then set the class name according to whatever you call your subclass (RedView here) under the identity inspector of the interface builder. If you want to change the background color programatically, wire up the view object. Then do something like the following.

import Cocoa

class MyView: NSView {
    // MARK: - Variables
    var backgroundColor = NSColor()

    // MARK: - Draw
    override func draw(_ rect:NSRect) {
        super.draw(rect)
        backgroundColor.set()
        NSRectFill(rect)
    }

    // MARK: - Method
    func changeBackgroundColor(color: NSColor) {
        backgroundColor = color
        setNeedsDisplay(self.bounds)
    }
}

You can then call changeBackgroundColor from the view controller like...

@IBOutlet weak var myView: MyView!
myView.changeBackgroundColor(color: NSColor.green)
like image 20
El Tomato Avatar answered Nov 04 '22 07:11

El Tomato