16

Is there a simple way to get an NSScrollView to adapt to its document view changing size when using auto layout?

I have tried to call both setNeedsUpdateConstraints: and setNeedsLayout: on the document view, the clip view and the scroll view, without any results.

fittingSize of the document view reports the correct size.

The problem is that the document view, which holds subviews, is not re-sized when the subviews change their size, even if they call invalidateIntrinsicContentSize. The contents of the document view are hence clipped to the original size of the document view as they grow. The document view is created in a nib and set as the scroll view's document view in an awakeFromBib method.

I was hoping that the document view frame would automatically be adjusted when its fittingSize changes, and the scrollbars updated accordingly.

NSPopover does something similar - provided that the subviews of the content controller's view have the constraints set right and various content hugging values are high enough (higher than the hidden popover window's hight constraint priority, for one).

Monolo
  • 18,205
  • 17
  • 69
  • 103
  • I'm not sure I understand your intent -- a scroll view is meant to scroll over the whole length of its document view. Why do you want it to change size with the content view's size? – rdelmar May 29 '12 at 23:32

1 Answers1

15

The problem of course is that when adding the document view, Cocoa will automatically create some hard constraints in the view that the document view is inserted into, i.e., the clip view.

So the answer to my own question is simple, just use:

// Assume self.docView is an IBOutlet populated with
// an NSView subclass
self.docView.translatesAutoresizingMaskIntoConstraints = NO;

before you add the document view to the scroll view:

self.scrollView.documentView = self.docView;

Now, since there are no auto-generated constraints on the layout of the document view in the clip view, you will need to add them explicitly. Otherwise, the doc view's contents will just be rendered at their intrinsic size in the upper left corner of the scroll view.

Monolo
  • 18,205
  • 17
  • 69
  • 103
  • Does anyone have any tips for doing this with a scrollview & subviews created in IB rather than setup in code? One idea: manually remove the automatically-added constraints in awakeFromNib, replace with my own. Another idea: remove document view from its superview, add it back after setting flag. I'll post again if I find that one of these works well. – Pierre Houston Jan 03 '13 at 20:04
  • 4
    Yes, the second idea worked. For views I setup in IB, I have awakeFromNib remove the documentView from its superview, set translates.. to NO & add it back. Finally it adds the constraints @"H:|[docview]|" and @"V:|[docview]" to docview.superview. – Pierre Houston Jan 03 '13 at 21:14
  • Do you have some more demo code for this? Especially showing the constraints you add? Kind of stuck at this ;-) – Andreas Zöllner Apr 07 '15 at 14:46
  • If you override `- (NSSize)intrinsicContentSize` in the subclass that is the scroll view's documentView, the scroll view will add its own constraints of type `NSContentSizeLayoutConstraint`, even if `translatesAutoresizingMaskIntoConstraints=NO` on the documentView. These constraints set the width, height, content hugging, and compression resistance. The constraints may differ from the size returned from `-intrinsicContentSize`. If you don't override `-intrinsicContentSize`, `translatesAutoresizingMaskIntoConstraints=NO` stops the scroll view from adding its constraints to the document view. – Andrew Aug 03 '17 at 05:21