Подтвердить что ты не робот

Использование Autolayout с расширением NSTextViews

Мое приложение состоит из NSScrollView, представление документа которого содержит несколько вертикально расположенных NSTextViews - каждый из которых изменяется в вертикальном направлении по мере добавления текста.

В настоящее время все это управляется кодом. NSTextViews изменяет размер автоматически, но я наблюдаю их изменение размера с помощью NSViewFrameDidChangeNotification, recalc все их происхождение, чтобы они не перекрывались и изменяли размер своего супервизора (вид документа с прокруткой), чтобы они все соответствовали и могут быть прокручены к.

Кажется, что это был бы идеальный кандидат на автозапуск! Я установил NSLayoutConstraints между первым текстовым видом и его контейнером, последним текстовым видом и его контейнером, а также каждым текстовым видом между собой. Затем, если какой-либо текстовый вид растет, он автоматически "толкает" истоки текстовых представлений под ним, чтобы удовлетворить противоречия, в конечном счете увеличивая размер представления документа, и все счастливы!

Кроме того, кажется, что нет способа сделать NSTextView автоматически растущим, поскольку текст добавляется в макете с ограничениями? Используя тот же самый NSTextView, который автоматически расширялся по мере ввода текста до этого, если я не укажу ограничение для его высоты, он имеет значение 0 и не отображается. Если я задаю ограничение, даже такое неравенство, как >= 20, оно остается застрявшим в этом размере и не растет с добавлением текста.

Я подозреваю, что это связано с реализацией NSTextView -intrinsicContentSize, которая по умолчанию возвращает (NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric).

Итак, мои вопросы: если я подклассифицирую NSTextView для возврата более значимого intrinsicContentSize на основе макета моего текста, будет ли мой автозапуск работать как ожидалось?

Любые указатели на реализацию intrinsicContentSize для вертикального изменения размера NSTextView?

4b9b3361

Ответ 1

У меня была аналогичная проблема с NSTextField, и оказалось, что это было из-за представления, которое нужно было обнимать его текстовое содержимое по вертикальной ориентации. Поэтому, если вы установите приоритет обхода контента на что-то ниже приоритетов других ограничений, это может сработать. Например:.

[textView setContentHuggingPriority:NSLayoutPriorityFittingSizeCompression-1.0 forOrientation:NSLayoutConstraintOrientationVertical];

Ответ 2

Я работаю над очень похожими настройками - вертикальный стек представлений, содержащий текстовые представления, которые расширяются, чтобы соответствовать их содержимому текста и использовать автозапуск.

До сих пор мне приходилось подклассом NSTextView, который не чувствует себя чистым, но на практике работает превосходно:

- (NSSize) intrinsicContentSize {
    NSTextContainer* textContainer = [self textContainer];
    NSLayoutManager* layoutManager = [self layoutManager];
    [layoutManager ensureLayoutForTextContainer: textContainer];
    return [layoutManager usedRectForTextContainer: textContainer].size;
}

- (void) didChangeText {
    [super didChangeText];
    [self invalidateIntrinsicContentSize];
}

Исходный размер текстового представления при добавлении addSubview, с любопытством, не является внутренним размером; Я еще не понял, как выдать первое недействительное (привязка viewDidMoveToSuperview не помогает), но я уверен, что в конце концов это выясню.

Ответ 3

Вот как сделать расширяющийся NSTextView с помощью Auto Layout, в Swift 3 введите описание изображения здесь

  • Я использовал Anchors для автоматической компоновки
  • Используйте textDidChange из NSTextDelegate. NSTextViewDelegate соответствует NSTextDelegate
  • Идея состоит в том, что textView имеет ограничения edges, что означает, что всякий раз, когда изменяется его intrinsicContentSize, он расширит родительский элемент, который равен scrollView

    import Cocoa
    import Anchors
    
    class TextView: NSTextView {
      override var intrinsicContentSize: NSSize {
        guard let manager = textContainer?.layoutManager else {
          return .zero
        }
    
        manager.ensureLayout(for: textContainer!)
    
        return manager.usedRect(for: textContainer!).size
      }
    }
    
    class ViewController: NSViewController, NSTextViewDelegate {
    
      @IBOutlet var textView: NSTextView!
      @IBOutlet weak var scrollView: NSScrollView!
      override func viewDidLoad() {
        super.viewDidLoad()
    
        textView.delegate = self
    
        activate(
          scrollView.anchor.top.constant(100),
          scrollView.anchor.paddingHorizontally(30)
        )
    
        activate(
          textView.anchor.edges
        )
      }
    
      // MARK: - NSTextDelegate
      func textDidChange(_ notification: Notification) {
        guard let textView = notification.object as? NSTextView else { return }
    
        print(textView.intrinsicContentSize)
        textView.invalidateIntrinsicContentSize()
      }
    }