Как программно сделать multiline NSTextField изменяющийся по вертикали в зависимости от размера текста, macOS ?


#1

Добрый день!
В проекте есть кастомный NSView, в него как SubView добавляю при нажатии кнопки кастомный NSTextField. Нужно сделать так чтобы он был multiline и при введении текста автоматически изменялся размер по вертикали.

Для multiline использовал

textFieldView.usesSingleLineMode = false
textFieldView.cell?.wraps = true

Но с тем чтобы изменялся размер по вертикали возникла проблема. Понятно что надо в зависимости от текста менять frame size. Перепробовал несколько советов из stackoverflow
Один из них с использованием intrinsicContentSize. Второй - с использованием preferredMaxLayoutWidth и ничего не работает.

Может кто уже сталкивался с такой же проблемой. Подскажите что делать !!!


#2

Как тест, сделал NSTextField через interface builder и сделал его кастомным. В кастомном классе использовал код отсюда (DouglasHeriot в swift варианте) - https://stackoverflow.com/questions/14107385/getting-a-nstextfield-to-grow-with-the-text-in-auto-layout

Этот textField в результате заработал, меняем текст и высота textField меняется. Использовал этот же кастомный класс для NSTextField который добавляется в NSView как SubView при нажатии кнопки. NSTextField при этом содержит некоторый текст. Когда затем пытался менять этот текст, с первой же добавленной буквой NSTextField с текстом ужался и текст исчез, но видно по NSTextField рамке что NSTextField меняет frame, добавляю букву рамка увеличивается, убираю одну букву рамка остается прежней. В общем код по/видимому работает, но почему то текст исчезает.

Код для добаляемого NSTextField,

    let textFieldView = ResizingNSTextField(string: "Test text")
    textFieldView.usesSingleLineMode = false
    textFieldView.cell?.wraps = true
    textFieldView.cell?.isScrollable = false
    textFieldView.layout()

В кастомном NSTextField

    override func textDidChange(_ notification: Notification)
    {
        super.textDidChange(notification)
        invalidateIntrinsicContentSize()
        self.frame.size = NSMakeSize(self.intrinsicContentSize.width, self.intrinsicContentSize.height)
    }

Почему текст исчезает ?


#3

Ну, что решение нашел. Использовал напрямую, без использования intrinsicContentSize, информацию о textContainer (из DouglasHeriot ответа ) Код следущий, может кому пригодится.

class ResizingNSTextField: NSTextField
{
     override func textDidChange(_ notification: Notification)
     {
          var contentRect = CGRect()
    
          if let textView = self.window?.fieldEditor(false, for: self) as? NSTextView, let textContainer = textView.textContainer
          {
              contentRect = (textView.textContainer?.layoutManager?.usedRect(for: textContainer))!
              contentRect.size.height += 5.0 
          }
           self.frame.size = NSMakeSize(self.frame.size.width, contentRect.size.height)
    }
}