I have an outlineView in which I am putting NSTextViews that resize when edited (think outliner app). I have most of this working, but some behaviour is inconsistent.
On my NSOutlineView I set:
outlineView?.usesAutomaticRowHeights = true
For my cell-views I subclass NSTextView. I set the following auto layout bits:
self.translatesAutoresizingMaskIntoConstraints = false
setContentHuggingPriority(NSLayoutConstraint.Priority.defaultHigh, for: NSLayoutConstraint.Orientation.vertical)
And I override the intrinsic content size calculation on the NSTextView:
override var intrinsicContentSize: NSSize {
guard let manager = textContainer?.layoutManager else {
return .zero
}
print("\(manager.usedRect(for: textContainer!).size) \(string)")
return manager.usedRect(for: textContainer!).size
}
(I was calling ensureLayout on the layoutManager in the code above but it adds nothing)
intrinsicContentSize is called twice per text view when they are added to the outliner. The first time the size returned is correct, but on the second call some of the text wraps unnecessarily. A printout of the two passes on intrinsicContentSize for 4 text views are shown below. The column width is 281, so none of these strings should wrap. The first pass they all fit to one line (14 high), on the second pass, the last two strings wrap, which is strange because they are not the longest strings:
(178.744140625, 14.0) New pointwddwek kelekwelek...
(100.720703125, 14.0) Related Subjects
(119.400390625, 14.0) Related Publications
(87.150390625, 14.0) Related Terms
(178.744140625, 14.0) New pointwddwek kelekwelek...
(100.720703125, 14.0) Related Subjects
(74.705078125, 28.0) Related Publications
(54.484375, 28.0) Related Terms
It is consistently the same strings that result in the same behaviour. E.g. the string "Related Subjects" never wraps, the string "Related Terms" always wraps.
When the views are presented, the text is NOT actually wrapped, even thought the usedRect value implies that it would be. The text is shown correctly, but the row view in the outliner is too high because it thinks it has two lines of text.
Any pointers where I might be missing something? Does 'ensureLayout' somehow refer to it's previous calculation and then have rounding issues when fitting the same string into its last-calculated width?
OK, the key here was that the text was presented correctly but the size of the view was wrong.
I created a delagate for the NSTextView's layoutManager. The text was being set out 3 times after the NSTextView was added to the NSOutlineView (which seems to be terribly inefficient!). intrinsicContentSize was only being called on the NSTextView after the first two text layouts.
Calling invalidateIntrinsicContentSize from within layoutManager: didCompleteLayoutFor... fixed everything up.
I still don't understand what is happening here though, and why all these methods are being called so many times when stuff is presented. I guess it is to do with the complexity of auto layout and things pushing against each other.
I also don't understand why only some of the calculations were incorrect during the process.
Please comment here if anyone can shine some light on this!