Re: NSScrollView autolayout (10.10)
Re: NSScrollView autolayout (10.10)
- Subject: Re: NSScrollView autolayout (10.10)
- From: Ken Thomases <email@hidden>
- Date: Wed, 07 Jan 2015 10:57:08 -0600
On Jan 7, 2015, at 6:26 AM, Roland King <email@hidden> wrote:
> I want an NSStackView which can be scrolled. I dragged an NSScrollView out in IB, that gives me a scrollview, the scrollers, a clip view and a child NSView of the clip view, which IB doesn’t want you to delete. I dragged my NSStackView out and made it a child of that view
>
> +- NSScrollview
> +- NSClipView
> +- NSView
> +- NSStackView
>
> There were no constraints set up initially between anything and anything else. After a large amount of messing about I constrained the NSStackView to all 4 sides of its parent, non-deletable NSView. I then constrained that NSView top, left and right (but not bottom) to its parent, the ClipView. This almost worked, except the StackView grew from the bottom up, not the top down, so I subclassed NSClipView to return YES for isFlipped.
>
> This appears to actually work but I don’t entirely understand every piece of why. I think I understand why the NSView ends up being the intrinsic content size of the StackView, which is what I want, and why the clipview is allowed to be independent of that piece of content (only pinned on three sides). But I don’t understand what’s driving the contentSize of the scrollview for me.
If you didn't constrain the scroll view itself relative to its superview or sibling views, then constraints would have been generated at build time. (Select the scroll view and then the Size inspector. It will have a note to that effect.) Those constraints may not be appropriate for how you want it to behave (as you resize the window, for example). Better to add such constraints yourself. The scroll view's contentSize is implied by the scroll view's frame plus some of its properties. For example, that calculation is what +contentSizeForFrameSize:horizontalScrollerClass:verticalScrollerClass:borderType:controlSize:scrollerStyle: does.
> More generally, is this how you’re supposed to set up a view which has intrinsic content size inside a scroll view in IB, pin that view to the NSView IB gives you, then pin that to the clipview on 3 sides only and flip the clip (why?).
>
> I did try changing the class of the NSView I can’t delete to NSStackView and avoid the middle man, very bad things happened, constraints were generated in constraint language which didn’t parse, so I decided to put it back where it was.
For what it's worth, I dragged an NSStackView into a window. Then, I chose Editor > Embed In > Scroll View. That resulted in:
+- NSScrollview
+- NSClipView
+- NSStackView
Then I selected Reset to Suggested Constraints for the whole window. That added leading, trailing, top, and bottom constraints for the scroll view to its superview and the same for the stack view to the clip view. The fact that the stack view was constrained on all sides meant that it would never scroll. Rather, the scroll view would grow to fit it and the window would grow to fit that. I then deleted the bottom constraint between the stack view and the clip view, similar to what you have. That resulted in what you described: the stack view was positioned at the bottom of the clip view when it was shorter than the scroll view's content height.
I didn't try subclassing NSClipView to make it flipped. (I had thought that clip views were flipped by default, but that may not apply with auto layout.) I assume it would fix the placement of the stack view as you described.
There's another way to fix that, though. Rather than removing the bottom constraint between the stack view and the clip view, change it to an inequality. Make it so that the stack view is _at least_ as tall as the clip view (stack view bottom is greater than or equal to the clip view bottom). When the scroll view is taller than needed to show the stack view's intrinsic height, the stack view is made taller to fill the content size and thus subviews in its top section will appear at the top of the scroll view. When the scroll view is shorter than needed (either because the stack view grows or because the window is made smaller), the stack view is not forced to be shorter. Rather, it is allowed to scroll vertically, since the document (stack) view is taller than the content (clip) view.
Anyway, I didn't notice any problems with not having an extra NSView in the hierarchy between the clip view and the stack view.
By the way, there's an issue with the trailing constraint that's similar to the bottom constraint. If you leave the trailing constraint as an equality, then the window and scroll view won't be allowed to go narrower than the stack view. Conversely, if the stack view becomes wider because of one of its subviews, the window will increase in width to accommodate it. This may be desirable, but there are alternatives that you may prefer, depending on your design.
If you remove the constraint, the stack view will only be as wide as needed for its widest subview, if any has intrinsic width (directly or indirectly). If it's configured to align its subviews on the left, this doesn't much matter. If it's configured to align them horizontally centered or on the right, then this will affect where the subviews end up.
You could also make the trailing constraint an inequality as I suggested for the bottom constraint, so that the stack view is _at least_ as wide as the clip view. This will keep things aligned as you might expect when the scroll view is wide enough to show the entire width of the stack view. But it will allow the scroll view to be made narrower than the stack view, if desired. When that happens, the scroll view will enable horizontal scrolling (assuming it's configured to allow that).
Regards,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden