使用 Swift 和自动布局变得更高的 NSTextField

NSTextField That Grows Taller Using Swift and Auto Layout

Xcode 9.1, Swift 4

我正在尝试创建一个 NSTextField 高度随着用户输入文本而增加。就像 Mac 上的 iMessage 中的那个一样。这是一个示例视频:http://d.pr/v/zWRA6w

我已经像这样设置了 NSViews,这样我就可以在 NSTextField 周围进行自定义设计,并且只保留其默认边框和背景:

这是我的限制条件。聊天对话在聊天包装下方滚动。

我尝试遵循 this answer 并创建了以下 Swift 版本:

class ResizingTextField: NSTextField{
  var isEditing = false
  override func textDidBeginEditing(_ notification: Notification) {
    super.textDidBeginEditing(notification)
    isEditing = true
  }
  override func textDidEndEditing(_ notification: Notification) {
    super.textDidEndEditing(notification)
    isEditing = false
  }
  override func textDidChange(_ notification: Notification) {
    super.textDidChange(notification)
    self.invalidateIntrinsicContentSize()
  }
  override public var intrinsicContentSize: CGSize {
    if isEditing{
      let fieldEditor = self.window?.fieldEditor(false, for: self)
      if fieldEditor != nil{
        if let cellCopy = self.cell?.copy() as? NSTextFieldCell{
          cellCopy.stringValue = fieldEditor!.string
          return cellCopy.cellSize
        }
      }
    }
    return self.cell!.cellSize
  }
}

但我的约束 and/or 代码一定有问题,因为当我在框中键入时没有任何反应。

有什么建议吗?

我遇到了这个有效的方法:https://gist.github.com/entotsu/ddc136832a87a0fd2f9a0a6d4cf754ea

我必须稍微更新一下代码才能使用 Swift 4:

class AutoGrowingTextField: NSTextField {

  var minHeight: CGFloat? = 22
  let bottomSpace: CGFloat = 7
  // magic number! (the field editor TextView is offset within the NSTextField. It’s easy to get the space above (it’s origin), but it’s difficult to get the default spacing for the bottom, as we may be changing the height

  var heightLimit: CGFloat?
  var lastSize: NSSize?
  var isEditing = false

  override func textDidBeginEditing(_ notification: Notification) {
    super.textDidBeginEditing(notification)
    isEditing = true
  }
  override func textDidEndEditing(_ notification: Notification) {
    super.textDidEndEditing(notification)
    isEditing = false
  }
  override func textDidChange(_ notification: Notification) {
    super.textDidChange(notification)
    self.invalidateIntrinsicContentSize()
  }

  override var intrinsicContentSize: NSSize {
    var minSize: NSSize {
      var size = super.intrinsicContentSize
      size.height = minHeight ?? 0
      return size
    }
    // Only update the size if we’re editing the text, or if we’ve not set it yet
    // If we try and update it while another text field is selected, it may shrink back down to only the size of one line (for some reason?)
    if isEditing || lastSize == nil {

      //If we’re being edited, get the shared NSTextView field editor, so we can get more info
      guard let textView = self.window?.fieldEditor(false, for: self) as? NSTextView, let container = textView.textContainer, let newHeight = container.layoutManager?.usedRect(for: container).height
      else {
          return lastSize ?? minSize
      }
      var newSize = super.intrinsicContentSize
      newSize.height = newHeight + bottomSpace

      if let heightLimit = heightLimit, let lastSize = lastSize, newSize.height > heightLimit {
        newSize = lastSize
      }

      if let minHeight = minHeight, newSize.height < minHeight {
        newSize.height = minHeight
      }

      lastSize = newSize
      return newSize
    }
    else {
      return lastSize ?? minSize
    }
  }
}