More Layout Questions
Dave
Hi,
I have a couple of questions related to manual layout on the Mac. Using manual layout, does setting the “frame: of a view cause “layout” to be called or do I need to call “setNeedsLayout” specifically? In general, is there a particular way in which the NSView “layout” method is supposed to work or is it up to the developer to choose? From the docs: Override this method if your custom view needs to perform custom layout not expressible using the constraint-based layout system. In this case you are responsible for setting You may not invalidate any constraints as part of your layout phase, nor invalidate the layout of your superview or views outside of your view hierarchy. You also may not invoke a drawing pass as part of layout. You must call Should the “layout” method change the value of their “frame” property or should this be done by the superview? I have a View Hierarchy and when the window resizes, I change the sizes and positions of the views within each subview. It seem to me that there are two ways of doing it given the following Hierarchy: WindowTrackingView (.view) LeftAreaView ContainerViewA RightAreaView ContainerViewB So, when the window resized, WindowTrackingView::layout gets called with its “frame” property set to the new size. At this point there are two options: 1. WindowTrackingView::layout simply calls “setNeedsLayout” for each of its subviews and each subview sets their own frame based on the “frame" rectangle of the superview via their own “layout” method. 2. WindowTrackingView::layout calculates and sets the frame of each of its subviews based on its own “frame” in this case and then calls “setNeedsDisplay” (unless this is already done if the “frame” changes?). Is any of these methods preferred or is it up to the developer to choose based on the job in hand? Any help on this greatly appreciated, I’ve written a test app and have almost got my head around manual layout, I just need to understand if this last bit. Thanks in advance. All the Best Dave |
|
Sandor Szatmari
On Sep 21, 2018, at 08:36, Dave <dave@...> wrote:
Sandor
|
|
Quincey Morris
On Sep 21, 2018, at 05:36 , Dave <dave@...> wrote:
You seem to be way off base here. “Manual layout” is just the absence of auto-layout. The layout method is part of the auto-layout system, as the documentation says: "Perform layout in concert with the constraint-based layout system.” It’s a way of customizing auto-layout, not doing manual layout. It sounds like you’re trying to auto-layout, but without any constraints. That’s certainly possible, but an auto-layout pass is still an auto-layout pass. is there a particular way in which the NSView “layout” method is supposed to work or is it up to the developer to choose? Yes, there’s a particular way. It needs to lay out its subviews (adjust the size and position of its subviews) by doing whatever isn’t being done by constraints. That means setting frames of its subviews. A view should not change *its own* frame in its "layout” method. That invalidates the layout of the superview, which is explicitly prohibited by the documentation you quoted.
No. Do *not* call “setNeedsLayout” from a “layout” method. That will trigger another layout pass, and layout will loop forever. As above, views are prohibited from setting their own frame in their own “layout” method.
Do not call “setNeedsDisplay” routinely here. The “layout” method is about layout, and you aren’t concerned with drawing here. (If changing the layout resizes some subviews, the resizing itself will trigger drawing as necessary. That’s the normal consequence of resizing views. You don’t have to do anything extra.) But, yes, you need to set the frame of each subview that isn’t going to be (before "[super layout]”) or hasn’t been ("after [super layout]”) set by auto-layout constraints. |
|
Dave
Typical! The way I chose to do it, layout sets in own frame rectangle and calls layout on its subviews, however, it seems to work wonderfully, so not sure what is going on! Any comments?
Noted, thanks.
Not sure what you mean by this? There are no constraints define in this Storyboard/NIB. In the following hierarchy: WindowTrackerView .view) SubviewA SubviewB SubviewC WindowTrackerView::layout sets the frame of SubviewA. SubviewA::layout sets the frame of SubviewB SubviewB::layout sets the frame of SubviewC Thanks a lot for the help All the Best Dave |
|
Dave
I meant to say: |
|
Quincey Morris
On Sep 21, 2018, at 08:07 , Dave <dave@...> wrote:
I mean that if you have disabled auto-layout, then you shouldn’t be trying to use auto-layout. Implementing the “layout” method comes under the heading of “trying to use auto-layout”, as the documentation says. It may be possible that “layout” gets called anyway (it would have no effect unless you overrode it to do something), but the behavior isn’t documented in that case. You can’t rely on it to behave in any meaningful way. |
|
Dave
Hi,
toggle quoted message
Show quoted text
I’m confused then! The “layout” method has been around a lot longer than Auto Layout and it worked in conjunction with the Auto-Resizing options (defined in the Size Pane in IB). I assumed that in order to customise my layout I would override “layout” as done in the past, is this not the case? You seem to be saying that If I want to layout my views myself, I don’t override the layout method or use setNeedsLayout? I could change the name of the method from “layout" to (say) “layoutView” for instance and instead of calling “setNeedsLayout” call “layoutView” on the subviews. However, at the moment when the window is resized, it initially calls “layout” in the WindowTracker view, do I still override this and “layoutView” on its subviews? The only other way of handling I can think of is to override setFrame and do the layout there, does that sound like a better approach? I’m just trying to find a decent way of laying out my views that’s fits into the way Cocoa works these days….. Any advice or suggestions greatly appreciated. All the Best Dave
|
|
Keary Suska
On Sep 22, 2018, at 5:29 AM, Dave <dave@...> wrote:This is incorrect: “layout” methods were added when autolayout was introduced in Lion (10.7). Before that, you used “frame” and “display” methods, and it was generally the responsibility of the superview to resize its subviews when its frame changes. You seem to be saying that If I want to layout my views myself, I don’t override the layout method or use setNeedsLayout?Yes. I could change the name of the method from “layout" to (say) “layoutView” for instance and instead of calling “setNeedsLayout” call “layoutView” on the subviews. However, at the moment when the window is resized, it initially calls “layout” in the WindowTracker view, do I still override this and “layoutView” on its subviews?Where you put resize logic probably best depends on who knows the most about how views should be laid out. For a super view that auto resizes subviews, its -resizeSubviewsWithOldSize: method is called anytime its frame changes. That is a better place to perform resizing on subviews, since it will be called by any method that changes the view's frame. If you want each subview to manage itself, you would override -resizeWithOldSuperviewSize: in the view. IMHO, it makes more sense for the superviews to manage their subviews so you avoid a bunch of subclasses that do nothing but self-resizing. I’m just trying to find a decent way of laying out my views that’s fits into the way Cocoa works these days…..Honestly, that means using autolayout because that “is thew way Cocoa works these days” but I sympathize with a strong desire to avoid it, as well as there being a number of use cases it simply can’t handle. Keary Suska Esoteritech, Inc. "Demystifying technology for your home or business" On 21 Sep 2018, at 17:28, Quincey Morris <quinceymorris@...> wrote: |
|
Gary L. Wade
When you find a use case it doesn’t handle, consider the various container views available, and if those don’t help, definitely write a radar. Apple is always improving things, and if you report such a case, it helps everyone.
toggle quoted message
Show quoted text
-- Gary L. Wade
|
|
Dave
HI,
Thanks for this, I did something like this a long while back and must have confused the “Display” path with the “Layout” path, thanks for putting me on the right track again. The its written it will be very easy to change what I have already to do it the way you describe below. Honestly, that means using autolayout because that “is thew way Cocoa works these days” but I sympathize with a strong desire to avoid it, as well as there being a number of use cases it simply can’t handle. The amount of time it was taking to make the board for the game I am working on to work was ridiculous for the return. The number of constraints was enormous and it was really slow when resizing. Add to this that as soon as you wanted to change something it sometimes meant re-doing *lots* of constraints and still it wasn’t 100%. It’s not Auto-Layout itself, the underlying technology is really good and I’d love to use it, but the tools we have for creating the Layouts in the first place are just horrible and unforgiving. I think a lot of it is due to having everything shoved into one giant all-purpose window/tab in Interface Builder. IMO its needs a specialist window that is designed specifically for Auto-Layout generation. Where you put resize logic probably best depends on who knows the most about how views should be laid out. For a super view that auto resizes subviews, its -resizeSubviewsWithOldSize: method is called anytime its frame changes. That is a better place to perform resizing on subviews, since it will be called by any method that changes the view's frame. If you want each subview to manage itself, you would override -resizeWithOldSuperviewSize: in the view. IMHO, it makes more sense for the superviews to manage their subviews so you avoid a bunch of subclasses that do nothing but self-resizing.I’m in two minds on this, a lot of the work can be done in a View Base Class that the subviews inherit from, this means that each subview has minimum extra code, but you can override it if you want to. I’m actually working on a number of games that use (mostly) a common board, each Game-App, and I can pull in Custom Views for the Games if I like, just by either adding or replacing a View in the Hierarchy and can be done in IB with no or minimal code changes. Thanks again for your help. All the Best Dave On 22 Sep 2018, at 16:54, Keary Suska <cocoa-dev@...> wrote:On Sep 22, 2018, at 5:29 AM, Dave <dave@...> wrote:This is incorrect: “layout” methods were added when autolayout was introduced in Lion (10.7). Before that, you used “frame” and “display” methods, and it was generally the responsibility of the superview to resize its subviews when its frame changes. |
|
Dave
Hi, Cheers Dave
|
|