NSTextField 边距和填充? (斯威夫特)

问题描述 投票:0回答:3

我想知道是否有可能为

NSTextField
设置边距或填充?

我实现了一个或多或少的自定义外观 textField(此屏幕截图中的第一个)...

...使用此代码:

myTextField.wantsLayer = true
myTextField.layer?.cornerRadius = 2.0
myTextField.layer?.borderWidth = 1.0
myTextField.layer?.borderColor = CGColor(red: 0.69, green: 0.69, blue: 0.69, alpha: 1.0)

但是,感觉我必须在左侧添加一些填充,以便数字不会太靠近边框。这可能吗?

swift xcode swift3 padding nstextfield
3个回答
12
投票

没有简单明了的方法来做到这一点,但就像 AppKit 中的许多东西一样,一旦你弄清楚你需要子类化的东西,它就不会太难。我遇到了 Hem Dutt 的这个例子,在我对 macOS 10.12 的测试中,这种方法似乎运作良好。简而言之,您只需要子类化

NSTextFieldCell
并重写一些方法来更改文本框。这是 Swift 3 的一个变体:

class CustomTextFieldCell: NSTextFieldCell {

    private static let padding = CGSize(width: 4.0, height: 2.0)

    override func cellSize(forBounds rect: NSRect) -> NSSize {
        var size = super.cellSize(forBounds: rect)
        size.height += (CustomTextFieldCell.padding.height * 2)
        return size
    }

    override func titleRect(forBounds rect: NSRect) -> NSRect {
        return rect.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
    }

    override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) {
        let insetRect = rect.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
        super.edit(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, event: event)
    }

    override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) {
        let insetRect = rect.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
        super.select(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength)
    }

    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        let insetRect = cellFrame.insetBy(dx: CustomTextFieldCell.padding.width, dy: CustomTextFieldCell.padding.height)
        super.drawInterior(withFrame: insetRect, in: controlView)
    }

}

我在原来的基础上做了一个显着的改变——覆盖

cellSize(forBounds:)
以增加单元格的最小高度。我正在使用自动布局来自动调整单元格的大小,所以如果没有覆盖,我的文本就会被剪掉。


3
投票

我通常只是通过将 textField 放在容器视图中来做到这一点。您可以为视图提供任何您想要的角半径、边框等,然后使用您想要的任何填充将 textField 限制在内部。只需确保将 textField 的边框样式更改为“无”,否则您将能够在视图中看到它。

可能有一种方法可以像使用按钮一样更改内容插图,但我一直找不到它。


0
投票

除了@robotspacer 的出色答案外,我还添加了一些用于处理包装文本字段的实现。

class PaddingTextFieldCell: NSTextFieldCell {
    
    /// The paadding size. The default value is `CGSize(width:0, height: 0)`
    @IBInspectable var padding: CGSize = .init(width: 0, height: 0)
    
    override func cellSize(forBounds rect: NSRect) -> NSSize {
        var size = super.cellSize(forBounds: rect)
        size.height += padding.height * 2
        size.width += padding.width * 2
        return size
    }
    
    override func drawingRect(forBounds rect: NSRect) -> NSRect {
        let rect = super.drawingRect(forBounds: rect)
        return rect.insetBy(dx: padding.width, dy: padding.height)
    }
    
    override func titleRect(forBounds rect: NSRect) -> NSRect {
        let rect = super.titleRect(forBounds: rect)
        return rect.insetBy(dx: padding.width, dy: padding.height)
    }
    
    override func edit(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, event: NSEvent?) {
        let insetRect = rect.insetBy(dx: padding.width, dy: padding.height)
        super.edit(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, event: event)
    }
    
    override func select(withFrame rect: NSRect, in controlView: NSView, editor textObj: NSText, delegate: Any?, start selStart: Int, length selLength: Int) {
        let insetRect = rect.insetBy(dx: padding.width, dy: padding.height)
        super.select(withFrame: insetRect, in: controlView, editor: textObj, delegate: delegate, start: selStart, length: selLength)
    }
    
    override func drawInterior(withFrame cellFrame: NSRect, in controlView: NSView) {
        let insetRect = cellFrame.insetBy(dx: padding.width, dy: padding.height)
        super.drawInterior(withFrame: insetRect, in: controlView)
    }
    
}

我已经添加了

drawingRect(forBounds:)
。即使在我实现自动增长的地方,这也适用于包装的文本字段。

© www.soinside.com 2019 - 2024. All rights reserved.