I have a vague, and frustrating, auto-layout problem. This occurs in an NSPanel that contains a few buttons, fields, and an NSTableView. The cells of the table view are fairly complex, consisting of several nested NSStackViews, but when loaded everything appears the way it is supposed to.
Except, for two text fields that are aligned to the scroll view. They do not have the correct height, width, or alignment (although they appear just fine in IB).
IB doesn't report any layout issues with the views. At runtime, the Debug View Hierarchy tool reports a single warning: "Position and size are ambiguous for NSVisualEffectView".
My problem is that the NSVisualEffectView object has no constraints. I tried following the steps in Detecting Ambiguous Layouts and get nowhere:
sending hasAmbiguousLayout returns YES
sending exerciseAmbiguityInLayout doesn't appear to do anything
sending constraintsAffectingLayoutForOrientation: returns empty arrays for both orientations
I've read elsewhere that nesting NSStackViews can create ambiguous layouts, but I have no clue as to how to address that.
Has anyone encountered this or have a suggestion on how to proceed?
Note that I've tried various alternatives to the layout of the text fields, including aligning them to the superview instead of the table view, using high and low values for compression resistance, hugging, etc. It doesn't matter, I still the get NSVisualEffectView warning and they are not positioned correctly.
Related
In the Xcode 13 size inspector Layout dropdown what does "Inferred (Autoresizing Mask) mean? I.e. what is the behavior of choosing it over simply Autoresizing Mask?
A related aside, there is also a third choice "inferred constraints" that is sometimes present sometimes not present. It seems that with the Game app the behavior of dragging things like stack views into a view or duplicating stack views gives inconsistent behavior. I.e. the duplicated stack view gets different Layout choices.
If you choose Inferred, you allow Interface Builder to keep inferring. If you get this view involved with autolayout, it will infer Autolayout instead of Autoresizing.
But if you choose Autoresizing, you override Interface Builder. If you involve this view with autolayout, the auto resizing values will be translated into constraints, and you'll have to know what you're doing or you'll get a constraint conflict.
So my view is pretty simple to setup but I can't figure out how to do a specific task.
So what I need to do is take in an array of strings, each one of these strings are a country ISO3 format code which in turn have a corresponding flag associated with it. Now after I add the flags to the view I need to be able to set all the constraints.
So first I add the imagesviews to the view, that works fine but now when I get to the updateConstraints method I am unsure how to proceed since I have an unknown amount of subviews.
So each subview will be placed about 5 spaces apart from the flag before it and the top of the image and bottom of the image should span the views height.
How can I write code that handles an arbitrary number of subviews?
So first i add the imagesviews to the view
As you do that, also add each view's constraints. Since you are looping through the flags / image views, you know whether there was a previous image view and if you've taken a little care, you have a reference to it. Thus, there is actually not a lot of code — it's a loop, and not a very long one — and it isn't at all difficult.
As an alternative, I suppose you could use a UIStackView (if you are not running on iOS 8). It will just take all the image views and space them out with constraints for you; all you have to do is decide on its size, which you can presumably do by counting the image views.
I'm building a OS X application using Swift and Xcode 6.4 on OS X 10.10.5.
On a specific view of my application I would like to have a view like this one Xcode has on the Data Model Editor.
I tried to replicate this view using an OutlineView where each "row" would have a title and a TableView plus two buttons (for the plus and minus buttons). For tests purposes I've separated the title for the TableView+Buttons, something like this (this was one of many different attempts).
Everything is working as expected except the View that has the TableView+Buttons, that is never higher than 17 pixels. If I define everything in one view, I have the same problem. I've tried defining the needed constraints but in that case there is a problem with a constraint that seems automatic called NSView-Encapsulated-Layout-Height, that forces the height to 17 pixels:
NSLayoutConstraint:0x61800008ea10 'NSView-Encapsulated-Layout-Height'
> V:[NotesTable(17)] (Names: NotesTable:0x60000012e2e0 )
I'm not defining any constraint to 17 pixels, I've tried testing with some parameters that usually insert automatic constraints (autoresizesSubviews/translatesAutoresizingMaskIntoConstraints/autoresizingMask) but I was only able to translate that 'special' constraint to another format and the grow doesn't get bigger.
Tried to search the web but I only get cases where that Encapsulated constraint makes sense and is useful.
Do you know where or how can I disable that constraint or change its value to the height I need?
Table and outline views on OS X do not support automatically determining the row height from the dynamic height of the cell views. They either have an explicit static row height, a static row height determined by the design-time height of the cell views, or a dynamic row height determined by the delegate and its implementation of -tableView:heightOfRow: or -outlineView:heightOfRowByItem:.
For your case, you're going to have to implement the delegate method. Furthermore, the delegate method can't query the actual cell view because it may not exist and the outline view would need the row height before creating it. So, the delegate has to compute it some other way.
One way is to keep a standalone view hierarchy of a prototypical cell view. When the delegate is asked for the row height, it configures that view hierarchy as it would be for the actual cell view for that row/item, forces it to lay itself out, and then queries its height. Configuring the view hierarchy may be as simple as setting the objectValue of the top-level view (if it's an NSTableCellView, a control, or otherwise implements the setter). But if your delegate does other configuration, such as in its -outlineView:viewForTableColumn:item: method, then you'll need to replicate that for this prototype view hierarchy.
Also, when any factor that would affect a row's height changes, you have to call the outline view's -noteHeightOfRowsWithIndexesChanged: method to let it know that, so it will re-query your ...heightOfRow... method.
Finally, bare table views are not especially amenable to being constrained to sibling views or their superview. They really want to live in scroll views and continue using springs-and-struts to position and size themselves. See my answer to another question for a discussion of this. It is possible that this has been improved in recent versions of the OS. Anyway, you're going to have to observe the table view's frame-change notifications (and ask it to post such notifications) in order to know when it grows. And your ability to set constraints to relate it to any other views in the cell view hierarchy will be severely limited, because it will need translatesAutoresizingMaskIntoConstraints turned on.
Ok. I've been at this over and over. I've seen blogs and cocoa dev threads.
I've seen Kyle Sluder's proposed solution, but have yet to find a solution that really works.
How can you position subviews of an NSScrollView with auto layout?
Is it just silently broken ?
Nothing seems to work.
Ok, old question, but this particular issue is a personal bugbear of mine so I'll answer it anyway!
The first thing to note is that an NSScrollView contains an NSClipView, which itself has a view outlet called documentView. These are all added for you when you drag a new scroll view into your storyboard or nib file. By default, the document view is an NSView called simply "View". If you're using a custom view, you can just select this and set its type in the inspector on the right to whatever you want. Otherwise, you'll be adding subviews to it.
The big thing that is easy to miss here is that, by default, the document view has its layout set to 'Translates Mask Into Constraints'. This is fine if the content size will never, ever change, and if that's the case you can simply set the frame of the document view to whatever you want and leave it at that. If you want it to automatically resize itself to fit its content however, there's a few things you'll need to do.
First off, that document view needs to have a completely unambiguous size. If you're using a custom view, I'd recommend giving it an intrinsicContentSize. You should also set 'Intrinsic Size' in IB's inspector to 'Placeholder' and give it a suitable value, or you'll get a bunch of autolayout warnings. If your document view gets its size from its content, all of the subviews must be linked in an unbroken chain from top to bottom, and from left to right, such that the content knows exactly how big it ought to be. This is quite an art in itself, so I won't go into it. A simple example where you have only one subview would be to pin its top, bottom, leading and trailing constraints to its parent, but as noted above if you're doing this, you might as well just set the type of the document view.
Now the fun bit. Select your document view and set its layout to 'Automatic'. Next, add top, bottom, leading and trailing constraints to its superview with a suitable value. I'm using zero, but you might want a small border. Finally, select the TRAILING and BOTTOM constraints you just made and set them to '>=' (greater than or equal) and a priority of 500 or less. The priority is very important, as it has to be less than the priority that the clip view uses to determine its own minimum size. Too high and the clip view will be forced to remain larger than its content, making it impossible in turn for the scroll view to be smaller than its content, rendering it useless.
The technical details aren't important. Just remember to set the document view to layout: automatic, pin all edges, and make the trailing and bottom constraints >= and priority 500.
Note that this will cause your content to hug the top-left corner.
Have you tried setting the document view's setTranslatesAutoresizingMaskIntoConstraints to TRUE?
[_scrollView.documentView setTranslatesAutoresizingMaskIntoConstraints:YES];
I have an NSTabView which has 5 tabs. Each tab contains an NSTableView (which, as default, is nested in NSScrollView). This is all loaded from a xib file with autolayout turned on. I'd like each table to fully occupy it's respective tab. Using autolayout I select each tab and carefully setup the NSScrollView so that it snaps its top, bottom, lead, and trailing edges to superview. After I do this for the 5 tabs, I'll resize the xib to give it a test. When I cycle back through the tabs, some stay snapped to the superview and some do not. There appears to be some sort of order to this but it is beyond what I can explain.
What's really frustrating is that sometime this will run okay, and sometimes it will crash because of unsatifyable constraints. For now I am using springs/struts but I like autolayout and would like to get it working.
I am afraid that it is the nesting of the tables inside scroll views which is causing the issues.
If you lay this out your own nib, you should be able to reproduce it.
I am hopeful that this can be solved by adding NSLayoutConstraints at runtime, if OSX is anything like iOS's autolayout. Using IB you cannot assing constraints to anythign other than super and sibling (no cousins). This can be done at runtime.
I am hoping someone out there has encountered this issue and has a solution.
Why do the constraints in the layout show a fixed constant instead of auto? Could that be it?
You mentioned cousin constraints, I believe you can add in the in IB if you select two views in the document outline on the left hand side and then add a constraint. I'm unable to pick any two views in IB if I'm using the main window but I can do it in the document outline.
Lastly, you mention it will run okay sometimes but not others - and if that's the case it sounds like something else is adding constraints. Instruments should have a template for tracing constraints, if you can reproduce it you may get a clue to what is introducing the incompatible constraint.