【问题标题】:OSX NSTextField with layer background color not working具有图层背景颜色的 OSX NSTextField 不起作用
【发布时间】:2016-10-18 15:17:05
【问题描述】:

我有以下NSTextField 的子类(对应的子类NSTextFieldCell 用于间距[发现方法here])。我正在尝试更改“焦点”上的边框颜色和背景颜色,但它不起作用。

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)
    }
}

事实上,尝试将self.layer?.backgroundColor 设置为任何地方的任何东西似乎都行不通。我不能只在文本字段本身上设置backgroundColor,因为根据单元格,背景颜色是偏移的。

如何在NSTextField 子类的层上设置backgroundColor

【问题讨论】:

    标签: xcode macos cocoa appkit


    【解决方案1】:

    尝试将您设置的背景颜色代码放入viewWillDraw。例如:

    -(void)viewWillDraw {
        [super setBackgroundColor:[NSColor yellowColor]];
    }
    

    【讨论】:

    • 我不能只setBackgroundColor,因为基于单元格,背景颜色是偏移的。
    • 同样设置背景颜色的方法发生在viewWillDraw,它只是调用了一个方法来做到这一点(setBlurredStyles
    【解决方案2】:

    看起来像一个简单的问题......但需要大量的hacky代码。我有一些工作的 sn-p 给你。

    确保您的文本字段有图层支持!

    摆脱单元格中的所有自定义内容。 Apple 想尽快让它们退役......甚至不确定是否有任何有效的案例与单元格一起运行:

    class TGTextFieldCell: NSTextFieldCell {
    
    }
    

    接下来我们来看看实际的:

    class TGTextField: NSTextField
    

    定义一个持有焦点状态的属性:

    private var isFocused = false
    

    像原来一样覆盖成为第一响应者:

    override func becomeFirstResponder() -> Bool {
        if super.becomeFirstResponder() {
            isFocused = true
            return true
        } else {
            return false
        }
    }
    

    很遗憾,我们无法轻易捕捉到模糊的瞬间。互联网上有一些很长的解释......但我们将在事件订阅中捕获模糊:

        func subscribeForEndEdit(){
        self.drawsBackground = false
        NSNotificationCenter.defaultCenter().addObserver(self, selector:"didEndEdit:", name: NSControlTextDidEndEditingNotification, object: nil)
    }
    
    func didEndEdit(notification: NSNotification){
        isFocused = false
    }
    

    现在在构造函数中调用该订阅覆盖:

    override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
    
        subscribeForEndEdit()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
    
        subscribeForEndEdit()
    }
    

    现在阻止背景绘制:

        self.drawsBackground = 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
        }
    
    
    }
    

    整个文件是:

    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 {
    
    }
    

    这是我得到的图片:

    【讨论】:

    • 感谢您的详尽回复!但是,我不能摆脱单元格,除非我可以重现在文本字段内填充填充的方式,就像我对单元格子类所做的那样。如果你能指出我这样做的方法,我肯定会放弃牢房(并接受你的回答:))。
    • 我说过要为特定的后台业务摆脱单元格。你可以肯定地保留你的手机。我刚刚粘贴了你所有的代码,它工作了。 class TGTextFieldCell: NSTextFieldCell { 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) } }自己试试。不过,您可能需要更改实际数字。填充看起来比需要的要深一些。
    • 好的!这很好用,我只需要像我一样覆盖becomeFirstResponder 并调用super.becomeFirstResponder 来包装设置变量并返回true(即使它没有成为第一响应者也可能调用)?有什么理由我不应该这样做,还是我可以编辑你的答案以包括那一点?
    • 您可以尝试覆盖 becomeFirstResponder,但我认为没有理由从队列中跳转。这对我来说没有意义。它看起来像一种 Javascript 方法,您可以在其中退出主循环以推迟操作...但我不确定它在 Apple 世界中的工作方式是否相同...如果您只是在某个变量中捕获 super.becomeFirstResponder() 则可以,但是正如我之前所说,这始终返回 true,直到您有明确的逻辑来阻止用户进出。如果您确实有这样的逻辑,那么是的,也许原始代码是有意义的(尽管没有插队)。但这与背景无关
    • 是的,我实际上不再获取主队列,只是在设置 var 并返回 true 之前检查 super.becomeFirstResponder 是否返回 true。我以前玩过它,但它没有更新 UI,我记得在某处读过你应该始终更新主队列上的 UI,所以我尝试了它并修复了它。但是,我不再使用它了,它工作正常。
    猜你喜欢
    • 1970-01-01
    • 2018-04-23
    • 2014-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多