I have three NSViews inside an NSTableCellView. Depending on the data for the row, I want to show a selected role with a border on the NSView like this:
The blue border NSView is a subclass that looks like this:
class RolePill: NSView{
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
layer?.cornerRadius = 9
layer?.borderWidth = 2
layer?.borderColor = NSColor.clear.cgColor
}
}
The role gets set initially when my table loads like this:
extension UsersVC: NSTableViewDelegate, NSTableViewDataSource{
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let cell = tableView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "UserCell"), owner: nil) as! UserCell
let user = users[row]
//Role
cell.setRole(role: user.role)
}
}
And my table cell, where the role gets set on load and on a button click, is set up like this:
class UserCell: NSTableCellView{
@IBOutlet weak var wrapOwner: RolePill!
@IBOutlet weak var wrapAdmin: RolePill!
@IBOutlet weak var wrapUser: RolePill!
@IBAction func clickOwner(_ sender: NSButton) {
setRole(role: "owner")
}
@IBAction func clickAdmin(_ sender: NSButton) {
setRole(role: "admin")
}
@IBAction func clickUser(_ sender: NSButton) {
setRole(role: "user")
}
func setRole(role: String){
let selectedColor = getAccentColor()
let offColor = Color(named: "BravoDark")!
let offTextColor = Color(named: "BFC0C2")
switch role{
case "owner":
wrapOwner.layer?.borderColor = selectedColor.cgColor
wrapAdmin.layer?.borderColor = offColor.cgColor
wrapUser.layer?.borderColor = offColor.cgColor
labelOwner.textColor = Color.white
labelAdmin.textColor = offTextColor
labelUser.textColor = offTextColor
case "admin":
wrapOwner.layer?.borderColor = offColor.cgColor
wrapAdmin.layer?.borderColor = selectedColor.cgColor
wrapUser.layer?.borderColor = offColor.cgColor
labelOwner.textColor = offTextColor
labelAdmin.textColor = Color.white
labelUser.textColor = offTextColor
default:
wrapOwner.layer?.borderColor = offColor.cgColor
wrapAdmin.layer?.borderColor = offColor.cgColor
wrapUser.layer?.borderColor = selectedColor.cgColor
labelOwner.textColor = offTextColor
labelAdmin.textColor = offTextColor
labelUser.textColor = Color.white
}
}
}
When the table loads initially, and anytime it refreshes (tableView.reloadData()) I lose my border and it looks like this:
As you can see, the textColor is set correctly to white. But for some reason, the border isn't set until I actually click on one of the IBAction buttons and manually trigger a change.
I suspect this is some kind of layer drawing bug where the RolePill class is redrawing every time my NSTableView reloads, but I don't know how to get it to accept the initial role state sent in tableView viewForRow.
Any idea what I'm doing wrong here? Thanks!


I was able to get this to work by setting all the
NSViewproperties insidesetRole()like this:It seemed that the
draw()method on myRolePillsubclass was getting called frequently, so I couldn't set a border color in there since it doesn't know what the user's data state is.