Reputation: 1665
I have the following subclass of NSTextField
(with corresponding subclass of NSTextFieldCell
for spacing [approach found here]). I'm trying to change the border color and background color on "focus", but it isn't working.
class TGTextField: NSTextField {
override func viewWillDraw() {
self.layer?.borderWidth = 1
self.layer?.cornerRadius = 2
self.textColor = NSColor(calibratedRed: 55/255, green: 54/255, blue: 54/255, alpha: 1)
self.focusRingType = .None
self.font = NSFont(name: "ProximaNova-Medium", size: 16)!
setBlurredStyles()
}
private func setFocusedStyles() {
self.layer?.borderColor = NSColor(calibratedRed: 92/255, green: 188/255, blue: 214/255, alpha: 1).CGColor
self.layer?.backgroundColor = NSColor(calibratedRed: 247/255, green: 252/255, blue: 252/255, alpha: 1).CGColor
}
private func setBlurredStyles() {
self.layer?.borderColor = NSColor(calibratedRed: 221/255, green: 221/255, blue: 221/255, alpha: 1).CGColor
self.layer?.backgroundColor = NSColor.whiteColor().CGColor
}
override func becomeFirstResponder() -> Bool {
if super.becomeFirstResponder() {
dispatch_async(dispatch_get_main_queue(), {
self.setFocusedStyles()
})
return true
} else {
return false
}
}
override func resignFirstResponder() -> Bool {
if super.resignFirstResponder() {
dispatch_async(dispatch_get_main_queue(), {
self.setBlurredStyles()
})
return true
} else {
return false
}
}
}
class TGTextFieldCell: NSTextFieldCell {
override init(imageCell image: NSImage?) {
super.init(imageCell: image)
}
override init(textCell aString: String) {
super.init(textCell: aString)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func drawingRectForBounds(theRect: NSRect) -> NSRect {
let rectInset = NSMakeRect(theRect.origin.x + 7, theRect.origin.y + 7, theRect.size.width, theRect.size.height)
return super.drawingRectForBounds(rectInset)
}
}
In fact, it appears that trying to set self.layer?.backgroundColor
to anything anywhere doesn't work. I can't just set backgroundColor
on the textfield itself, because based on the cell, the background color is offset.
How can I set the backgroundColor
on the layer of an NSTextField
subclass?
Upvotes: 4
Views: 2575
Reputation: 1180
Looks like a simple problem... but requires a lot of hacky code. I have some working snippet for you.
Make sure your text fields are layer backed!
Get rid of all that custom stuff in the cell. Apple want to retire them soon... Not even sure any valid cases operate with cells:
class TGTextFieldCell: NSTextFieldCell {
}
Next we get to the actual:
class TGTextField: NSTextField
Define a property holding focused state:
private var isFocused = false
Override becoming first responder as you did originally:
override func becomeFirstResponder() -> Bool {
if super.becomeFirstResponder() {
isFocused = true
return true
} else {
return false
}
}
Unfortunately, we cannot capture the moment of blur easily. There are some long explanations for that in internet... but we will capture blur in a the event subscription:
func subscribeForEndEdit(){
self.drawsBackground = false
NSNotificationCenter.defaultCenter().addObserver(self, selector:"didEndEdit:", name: NSControlTextDidEndEditingNotification, object: nil)
}
func didEndEdit(notification: NSNotification){
isFocused = false
}
Now call that subscription in the constructors overrides:
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
subscribeForEndEdit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
subscribeForEndEdit()
}
Now prevent background drawing:
self.drawsBackground = false
The final piece is changing background on drawing:
override func drawRect(dirtyRect: NSRect) {
//Draw cell content here
super.cell?.drawInteriorWithFrame(dirtyRect, inView: self)
if isFocused {
self.layer?.backgroundColor = NSColor.redColor().CGColor
} else {
self.layer?.backgroundColor = NSColor.whiteColor().CGColor
}
}
The entire file is:
import Cocoa
class TGTextField: NSTextField {
private var isFocused = false
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
subscribeForEndEdit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
subscribeForEndEdit()
}
func subscribeForEndEdit(){
self.drawsBackground = false
NSNotificationCenter.defaultCenter().addObserver(self, selector:"didEndEdit:", name: NSControlTextDidEndEditingNotification, object: nil)
}
func didEndEdit(notification: NSNotification){
isFocused = false
}
override func drawRect(dirtyRect: NSRect) {
//Draw cell content here
super.cell?.drawInteriorWithFrame(dirtyRect, inView: self)
if isFocused {
self.layer?.backgroundColor = NSColor.redColor().CGColor
} else {
self.layer?.backgroundColor = NSColor.whiteColor().CGColor
}
}
override func becomeFirstResponder() -> Bool {
if super.becomeFirstResponder() {
isFocused = true
return true
} else {
return false
}
}
deinit {
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
class TGTextFieldCell: NSTextFieldCell {
}
Here is the picture of what I get:
Upvotes: 4
Reputation: 75
try to put your set background color code in viewWillDraw
. For example:
-(void)viewWillDraw {
[super setBackgroundColor:[NSColor yellowColor]];
}
Upvotes: -3