On 3/16/13 3:05 PM, "Kyle Sluder" <[email protected]> wrote:
>On Mar 16, 2013, at 12:46 PM, Chuck Soper <[email protected]> wrote: > >> Are there similar notes on how to use autolayout with NSScrollView? Does >> anyone know the specific details on what Apple recommends? For example, >> are both mixed and pure autolayout approaches okay with NSScrollView? >>(The >> mixed or pure autolayout terminology comes from the UIScrollView notes - >> link above.) > >There is no official recommendation, but I have had a *lot* of experience >in this area. And I've been meaning to write a blog post about this as a >follow-up to my Xcoders presentation on auto layout, so consider this a >draft! > >The biggest issue with using auto layout in an NSScrollView's document >view is that NSScrollView itself is completely unaware of auto layout. >Thus, it relies on the behavior provided by setting >translatesAutoresizingMaskIntoConstraints=YES on its subviews so it can >continue to use -setFrame: to position them even if auto layout is turned >on for the window. > >At this point it's worth noting another difference between NSScrollView >and UIScrollView: UIScrollView directly manipulates its own bounds.origin >to perform scrolling of its entire subview hierarchy. The contentSize >property dictates the size of the scrollable region. > >NSScrollView, on the other hand, doesn't actually do any scrolling on its >own: it delegates that responsibility to an NSClipView. The scroll view >positions the clip view and scrollers (if they are visible) using >-setFrame:. Rather than exposing a contentSize property, NSClipView >observes the frame of _one specific subview_ called its documentView. >This view's frame.size becomes the equivalent of UIScrollView's >contentSize. > >In order to perform scrolling correctly, the documentView's frame.origin >must lie at (0,0) in the clip view's bounds coordinate system. >NSClipView, like NSScrollView, is unaware of auto layout, so it uses >-setFrameOrigin: to put the document view at (0,0). If auto layout gets >turned on for the window, this position gets turned into a pair of >constraints with a priority of 1000 (required). > >Two more constraints will be synthesized to define the width and height >of the document view. These constraints are the problem. In either >direction, one of two kinds of constraints will be generated, depending >on the documentView's autoresizing mask for that direction: > >1. If the view is stretchable in that direction, a constraint will be >installed relating the opposing edge of the documentView to the edge of >the superview. > >2. If the view is not stretchable in that direction, a constraint will be >installed dictating the absolute value of the documentView's frame.size >in that dimension. > >Like all autoresizing-mask constraints, these constraints are required >(priority 1000). Because the entire constraint system is solved at once, >it should be intuitive that any constraints that attempt to influence the >size of the documentView will conflict with either the constraints >installed by the clip view on the documentView and/or with the >constraints installed by the scroll view on the clip view. > >So we have a dilemma. We need to somehow break the bidirectionality of >the relationship between the clip view and the documentView. There is no >straightforward way to express this using the constraints API, but it is >indeed possible without resorting to mucking with private internal >details. > >In other words, we want to somehow run layout of arbitrary constraints on >our documentView's subtree and retrieve the resultant frame of the >documentView without involving the documentView itself in our constraint >system. Once we have the right values, we can use -setFrameSize: on the >documentView; the clip view will notice and it will update its scrollable >area. > >The way we accomplish this is to install another view in our subtree and >define all our constraints relative to _that_ view. I'm going to call >this the adaptor view. The documentView installs constraints to keep the >adaptor view's top and leading margins equal to zero, but critically it >does NOT install any constraints on the trailing or bottom edges. This >leaves the adaptorView's width and height free to be defined by its >content's layout. > >The documentView signs up for frame change notifications from the adaptor >view. Whenever it changes its frame, the documentView calls [self >setFrameSize:] with the same size. Then the clip view hears about this, >and the scroll view reflects the correct document size. For this to work, >the documentView's autoresizing mask should be set to width and height >NON-stretchable, that way when the clip view resizes (perhaps during >window dragging) it doesn't resize your documentView. > >If you're laying out the contents of your scroll view in IB, the most >convenient approach is to make the adaptor view the only subview of your >documentView, and to add all your widgets as subviews of the adaptor >view. The bonus here is that if your constraints are insufficient to >fully specify the frame of the adaptor view, IB will doggedly insist on >adding margin or fixed-size constraints until you fix your layout. Yes, >we have turned one of IB's most annoying habits into a feature! > >If you're generating all your constraints in code, however, it might be >just as convenient to make your adaptor view a _sibling_ of all your >widgets and to call -setHidden:YES on it, thus removing a level of >hierarchy between the documentView and your widgets. This is an excellent in-depth description and a great follow-up to your Seattle Xcoders talk from last January. You described your solution at the Seattle Xcoders meeting as a bit of a hack. Would you describe this revised approach as more stable. I've seen a number of developers on cocoa-dev and stack overflow that describe less-involved solutions such as just adding a couple of constraints to the clip view. On the other hand, I've never been able to implement those easier solutions in my own code. I really wish that Apple could provide official guidance with a tech note and/or some sample code. A lot of people are using auto layout with NSScrollView. Others are avoiding auto layout. >> >> I think that autolayout is a great technology. > >Me too, but it will be even better when AppKit fully supports it. All the >logic I described above could be added to NSClipView, and suddenly >NSScrollView would be constraint-aware. > >Let's see what 10.9 brings. > >--Kyle Sluder Should we file radars to be more proactive? Chuck _______________________________________________ Cocoa-dev mailing list ([email protected]) 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to [email protected]
