Поддержка автоматического размещения для настраиваемого просмотра текста - PullRequest
0 голосов
/ 05 марта 2019

Этот вопрос касается поддержки настраиваемого текстового представления переменной высоты с использованием ограничений и представления intrinsicContentSize для autolayout.Прежде, чем вы нажмете эту кнопку «дубликата», выслушайте меня.

У меня есть собственное представление текста (с нуля, наследуется от NSView).Он поддерживает многие обычные функции NSTextView, наиболее релевантными здесь являются несколько строк и расположение их содержимого на основе доступной ширины.Приложение, для которого оно создано, загружает несколько этих текстовых представлений в каждую строку табличного представления.Проблема в том, что высота не установлена ​​должным образом в соответствии с его intrinsicContentSize.

Я создал пример проекта , который упрощает проблему.Он использует «псевдо» текстовое представление с фиксированным числом и размером символов, используемое для определения требуемой ширины / высоты.В этом примере есть табличное представление одного столбца, представление ячейки которого имеет только одно подпредставление, PseudoTextView.Текстовое представление прикреплено к краям его представления ячейки с небольшим дополнением.Как я могу заставить систему распознавать, что текстовое представление должно подчиняться ограничениям, которые определяют ширину, в то же время позволяя текстовому виду увеличиваться по высоте, плотно обтянутому представлением ячейки?Вот код текстового представления:

class PseudoTextView: NSView {
@IBInspectable var characterCount: Int = 0
@IBInspectable var characterWidth: CGFloat = 5
@IBInspectable var characterHeight: CGFloat = 8
@IBInspectable var background: NSColor = .blue {
    didSet {
        layer?.backgroundColor = background.cgColor
    }
}

required init?(coder decoder: NSCoder) {
    super.init(coder: decoder)
    wantsLayer = true
    layer?.backgroundColor = background.cgColor
}

override var intrinsicContentSize: NSSize {
    let requiredWidth = characterWidth * CGFloat(characterCount)
    let lineCount = (requiredWidth / frame.width).rounded(.up)
    let usedHeight = lineCount * characterHeight
    let charactersPerLine = (frame.width / characterWidth).rounded(.down)
    let usedWidth = charactersPerLine * characterWidth
    return NSSize(width: usedWidth, height: usedHeight)
}

Эта версия возвращает соответствующий размер в зависимости от кадра представления.Это, очевидно, не работает, потому что к нему обращаются во время фазы макета updateConstraints, когда кадр не был установлен.Я также попытался использовать NSView.noIntrinsicMetric для ширины, но это приведет текстовое представление к нулевой ширине, и высота никогда не восстанавливается.Я сделал огромное количество других попыток, но я не буду утомлять вас ими.

NSTextField делает что-то другое (при условии, что 'Editable' выключен, 'Wrap' включен).Это intrinsicContentSize сообщает всю ширину текста в одной строке (даже если она намного длиннее доступной ширины), но его размер каким-то образом изменяется до правильной ширины.После изменения размера intrinsicContentWidth по-прежнему сообщает полную ширину одной строки, но высота корректируется для учета нескольких строк.Где-то есть магия, которую я не смог разгадать.

Я прочитал каждую строку соответствующей документации.Если в теме есть пост в блоге, я, наверное, его прочитал.Если есть вопрос о SO по этой теме, я, вероятно, прочитал его.Если вы написали книгу на эту тему, я, вероятно, купил ее.Все эти источники дразнят мою проблему, но ни один из них не отвечает на вопрос, как справиться с этой конкретной ситуацией.Отчаянно.

Обновление:

После прочтения старого сообщения в блоге Джонатона Маха (http://devetc.org/code/2014/07/07/auto-layout-and-views-that-wrap.html) я создал пример, использующий его подход. Вот другой проект это имитирует его технику и работает правильно. Это верхняя часть приложения. Это фиксированный вид контейнера, который настраивается с помощью ползунка. Пэчворк - это псевдосимволы пользовательского вида, фон которого - розовый.

enter image description here

Тем не менее, при вставке в представление таблицы с автоматическими размерами пользовательское представление правильно соответствует ширине его ячейки, но ячейка не регулируется в соответствии с внутренней высотойЕсли вы измените нижнее ограничение пользовательского представления на необязательное (скажем, с отношением> =), пользовательское представление сжимается до правильной высоты, но представление ячейки остается фиксированным. Как убедить представление ячейки уменьшить его высоту доуважать intrinsicContentSize.height его подпредставления?

enter image description here

1 Ответ

0 голосов
/ 07 марта 2019

У меня есть решение вашей проблемы, хотя оно может быть неоптимальным, так как я не слишком разбираюсь в специфике macos.Итак, во-первых, давайте определим, что табличное представление должно использовать автоматическую высоту строки:

override func awakeFromNib() {
    super.awakeFromNib()
    tableView.usesAutomaticRowHeights = true
}

Во втором примере розетка tableView не была подключена к TableViewController, но, вероятно, так и должно быть, поэтомуне забудьте подключить его.

Теперь в вашем WrappingCellView вы переопределяете layout(), но значение, установленное для preferredMaxLayoutWidth, неверно.Я думаю, это должна быть ширина суперпредставления:

override func layout() {
    // 16 is used for the sake of example
    wrappingView.preferredMaxLayoutWidth = (superview?.frame.width ?? 16) - 16
    super.layout()
}

Следующая часть - та, в которой я не уверен:

func tableViewColumnDidResize(_ notification: Notification) {
    tableView.reloadData()
}

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

Эти три корректировки приводят к правильному пересчету высоты ячейки: enter image description here

...