Daniel Farrell
Daniel Farrell

Reputation: 9750

Centring a NSScrollView's document view like Preview.app?

I am asking a question almost exactly the same as Trouble with autolayout on NSScrollView's document view. The solution of this question was to set translatesAutoresizingMaskIntoConstraints to NO in -awakeFromNib:.

However, for me (I am using Xcode 5), this flag is already set to NO when loading the nib so I seem to be running into a different issue.

I would like to replicated the way Preview.app details with image zooming, just using layout constraints (if possible). When the image size is less than the content view bounds the full image is displayed. However, when the image is zoomed the scroll bars activate to allow navigation. This seems simple enough. Below is the view hierarchy I have constructed. Note that the image view is contained inside a custom NSView (this is because I have been following the previous question approach where the custom view draws a background), this container view is to the NSScrollView's documentView and than the views where embedded inside the scroll view using the IB's Embed In command.

Zooming an image in a scroll view.

I have setup the following constraints in IB:

These constraints are not ambiguous, but I don't understand why the image is not centred?

Image not centered!

Upvotes: 2

Views: 814

Answers (2)

Ash
Ash

Reputation: 9351

Old question, but here's a modern solution that doesn't require subclassing. There are four views involved here:

  • The Scroll View is the NSScrollView itself.
  • The Clip View is an NSClipView contained within the scroll view.
  • The Content View is the NSView inside the Clip View.
  • The Image View is an NSImageView for showing your content.

So here's the process:

  1. Create your scroll view and place the image view inside its content view.
  2. Constrain all four of the image view's sides to equal the sides of the content view.
  3. Constrain the leading and top edges of the content view to the clip view.
  4. Set the content view's width and height to be greater than or equal to the clip view's.
  5. Set the image view's Scaling to None and alignment to centred.

Note that you could replace the NSImageView with more or less anything that supports content alignment and intrinsic content size. Alternatively, use an NSView, centre some other content inside it and pin that content's top and left edges to the parent. This will allow the NSView to infer its minimum size whilst keeping its child central.

Upvotes: 2

gaige
gaige

Reputation: 17491

This seems like a reasonable result given how you have described the problem. According to above, you have constrained:

  • The image contained view is constrained to have the same width and height as the image view (to draw a background/border, for example, it could be set to be slightly larger size).
  • The image container view is constrained to be centred in it's superview (i.e. NSScollView's clip view)
  • The scroll view is constrained to fill the contentView of the window.

The NSScrollView won't use auto layout to lay out the views within itself. Thus, by setting the image container view to be the size of the image, NSScrollView will pin that to the lower left (its origin point) when you have content that is too small.

When I've run into this same problem, I have done 2 things, each requiring some work and each reasonably successful, either:

  • Size the containing view to never be any smaller than the NSScrollView's content area and then center the NSImageView inside of that view. This gets the auto-centering inside of the containing view, but requires you to manipulate the containing view's size in order to not have a border when the image is zoomed in.

or

  • Remove the NSScrollView and center the containing view on the window when the containing view is too small to fill the NSScrollView.

Either way, you need to pay attention to when the window's and NSScrollView's content areas change and when the size of the NSImageView changes.

Upvotes: 1

Related Questions