Mac OS X Autolayout - expand to fill superview - macos

I have a nib. It has an NSScrollView with an NSTableView inside it. I would like this tableview to automatically expand to fill its entire superview.
I'm trying to use autolayout but I have no idea how to add the constraints. Since the nib has no view objects other than the scroll view - I don't get how you reference the superview.
None of the auto layout buttons at the bottom of the nib editor give me any options, everything is grayed out.
I'm using Interface Builder, Xcode 5, OS X 10.9.2.
Not iOS!

You can't. But you probably have the code where this view controller is instantiated. There you need to add constraints manually.

To get started have a look at the WWDC sessions, in particular
Auto Layout by Example (https://developer.apple.com/videos/wwdc/2012/)
Best Practices for Mastering Auto Layout (https://developer.apple.com/videos/wwdc/2012/)
The learning curve is a bit steep but it'll be worth your while.
Check out the Content Hugging setting for your view to make sure it's allowed to expand.
Also check the warnings in the Interface Builder editor and let it add missing constraints if you're not sure what to do.
And always pay attention to the Autolayout warnings in the Xcode console!
This blog post has some nice hints as well:
http://oleb.net/blog/2013/03/things-you-need-to-know-about-cocoa-autolayout/
Some more specific tips:
Autolayout is enabled for your .nib/.xib, right? Just making sure.
The super view is referenced kind of implicitly when you set the constraints for your view, you don't set constraints for the top-level view in the .xib (if I recall correctly, no Xcode at hand right now).

Related

Auto Resizing in Xcode 8

As I know, before XCode 7 appear, we have Auto Resizing go with Auto Layout (appear in XCode 5), but when XCode 7 appear, Auto Resizing be removed and this appeared again in XCode 8. My question are:
Why Apple put back this feature in XCode 8? Do this feature have
some new functions than previous?
We can use Auto Resizing with Auto Layout in the same page. What are
the benefits of using parallelism like that?
I searched in Apple document but not find info about Auto Resizing
Supply any document link or keyword will be appreciated. Thanks
Autoresizing wasn't removed previously, when autolayout was introduced. But in Interface Builder it was available only at the level of the individual xib or storyboard file: such a file either used exclusively autoresizing or exclusively autolayout. Your views configured in code could use either, but you couldn't mix and match with Interface Builder. The change in Xcode 8 is that now you can: one and the same xib or storyboard file can contain views some of which use autoresizing and some of which use autolayout (as you rightly say in your point 2).
The advantage is just what you think it is: freedom of choice, plus easy of use: sometimes autoresizing is all you need, and it can be much faster and simpler to configure. For example, if you want a button to be in the top left corner and stay in the top left corner, you just drag a button from the Library into the top left corner and leave it there; the button's autoresizing configuration is top-left by default, and this configuration won't be turned into autolayout constraints, but will simply be left as is.
However, if you then make a constraint to that button, you have involved it in autolayout, it will now use autolayout, and you will have to add proper constraints for it. In the past, an autoresizing view was "translated" automatically by Interface Builder into an autolayout view if it became involved in autolayout, with automatically generated "autoresizing constraints", but that no longer happens — and this too is a good thing, as it makes it less likely that you'll end up with an accidental conflict between manual constraints and autoresizing constraints.

Not using Auto Layout, yet see 'Unable to simultaneously satisfy constraints' error

I'm not using Auto Layout in any of my nib files. I'm loading a NSViewController and then adding its view to another NSView manually. However when I do that, I am seeing this error:
Unable to simultaneously satisfy constraints
This makes no sense to me since I don't have autolayout enabled anywhere. I have specifically disabled it. I have control over the NSViewController being loaded and the NSView I'm adding it's view to. What can I do to fix this?
Auto layout is enabled (or not) at the window level. If any view in the window has had constraints added to it or overrides +requiresConstraintBasedLayout to return YES, then auto layout is enabled for the window. Any views which are not coded to participate in auto layout would probably have translatesAutoresizingMaskIntoConstraints left on, so they would still work just as they would in a springs-and-struts window.
It's possible that, under certain circumstances, Cocoa might add constraints. Certain Cocoa views, such as NSStackView, return YES from +requiresConstraintBasedLayout.
Are you using some of the most recent features in your window, such as title bar accessories?

Problems with NSTabView autolayout (view based NSTableViews inside tabs)

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.

Can I disable autolayout for a specific subview at runtime?

I have a view that needs to have its frame manipulated programmatically - it's a kind of document view that wraps to its content which is then scrolled and zoomed around a superview by manipulating the frame origin. Autolayout fights with this at runtime.
Disabling autolayout completely seems a bit harsh because it could reasonably be used to handle layout for the other views. It seems like what I might want is some kind of "null constraint".
I had the same problem. But I have resolved it.
Yes, you can disable auto layout at runtime for a specific UIView, instead of disabling it for the whole xib or storyboard which is set by default in Xcode 4.3 and later.
Set translatesAutoresizingMaskIntoConstraints to YES, before you set the frame of your subview:
self.exampleView.translatesAutoresizingMaskIntoConstraints = YES;
self.exampleView.frame = CGRectMake(20, 20, 50, 50);
I had a similar issue where Autolayout was overriding some of my frame-setting at run time (I had a dynamic view that in some cases pushed a new view controller...pushing and then pressing Back would reset the initial view).
I got around this by putting my manipulation code in viewDidLayoutSubviews of my View Controller. This seems to get called after whatever constraint mojo gets called, but before viewDidAppear, so the user is none the wiser.
Perhaps just setting translatesAutoresizingMaskIntoConstraints to YES (and not adding additional constraints affecting that view) will let you set the frame without fighting the auto layout system.
In iOS 8 you can set an NSLayoutConstraint to be active or not. So if I'm using interface builder, I add all my constraints to an OutletCollection and then activate or deactivate using:
NSLayoutConstraint.deactivateConstraints(self.landscapeConstraintsPad)
NSLayoutConstraint.activateConstraints(self.portraitConstraintsPad)
The particular application I'm using it for here is having different constraints in portrait and landscape mode and I activate/deactivate based on the rotation of the device. It means I can create some complex layout changes all in interface builder for both orientations, and still use auto layout without the verbose auto layout code.
Or you can activate / deactivate using removeConstraints and addConstraints.
I don't know if this will help anyone else, but I wrote a category to make this convenient because I find myself doing this a lot.
UIView+DisableAutolayoutTemporarily.h
#import <UIKit/UIKit.h>
#interface UIView (DisableAutolayoutTemporarily)
// the view as a parameter is a convenience so we don't have to always
// guard against strong-reference cycles
- (void)resizeWithBlock:(void (^)(UIView *view))block;
#end
UIView+DisableAutolayoutTemporarily.m
#import "UIView+DisableAutoResizeTemporarily.h"
#implementation UIView (DisableAutoResizeTemporarily)
- (void)resizeWithBlock:(void (^)(UIView * view))block
{
UIView *superview = self.superview;
[self removeFromSuperview];
[self setTranslatesAutoresizingMaskIntoConstraints:YES];
__weak UIView *weakSelf = self;
block(weakSelf);
[superview addSubview:self];
}
#end
I use it like this:
[cell.argumentLabel resizeWithBlock:^(UIView *view) {
[view setFrame:frame];
}];
Hope it helps.
You can set the translatesAutoresizingMaskIntoConstraints type Boolean, Value Yes in the User Defined Runtime Attributes of the UIView you want in the xib/storyboard.
In my view I had a Label and a Text. The label had pan gesture. The label moves around fine during drag. But when I use the text box keyboard, the label resets its position to the original location defined in auto layout. The issue got resolved when I added the following in swift for the label. I added this in viewWillAppear but it can be added pretty much anywhere you have access to the target field.
self.captionUILabel.translatesAutoresizingMaskIntoConstraints = true
Open project in 4.5
Select storyboard
Open the file inspector
Under Interface Builder Document uncheck 'Use Autolayout'
You can split across multiple storyboards if you want to use autolayout for some views.
For me it worked to create the subview programmatically, in my case the auto layout was messing with a view that I needed to rotate around its center but once I created this view programmatically it worked.
I've encountered a similar scenario, where I joined a project that was initiated with auto-layout, but I needed to make dynamic adjustments to several views. Here is what has worked for me:
Do NOT have views or components laid out in interface builder.
Add your views purely programmatically starting with alloc/init and setting their frames appropriately.
Done.
This happened to me in a project without storyboards or xib files. All 100% code. I had an ad banner at the bottom and wanted the view bounds to stop at the ad banner. The view would resize itself automatically after loading. I tried every resolution on this page but none of them worked.
I ended up just creating a sub view with the shortened height and placed that in into the main view of the controller. Then all my content went inside the sub view. That solved the problem very easily without doing anything that felt like it was going against the grain.
I am thinking if you want a view that is not the normal size that fills the window then you should use a sub view for that.
Instead of disabling autolayout, I would just calculate the new constraint with the frame you are replacing. That appears to me to be the appropriate way. If you are adjusting components that rely on constraints, adjust them accordingly.
For example, if you have a vertical constraint of 0 between two views (myView and otherView), and you have a pan gesture or something that adjusts the height of myView then you can recalculate the constraint with the adjusted values.
self.verticalConstraint.constant = newMyViewYOriginValue - (self.otherView.frame.origin.y + self.otherView.frame.size.height);
[self.myView needsUpdateConstraints];
For those of you who are using auto layout, please check out my solution here. You should be making #IBOutlet's of the constraints you want to adjust and then change their constants.
if it's xib file:
select the .xib file
select the "File's Owner"
show the Utilities
click on: "File Inspector"
Under "Interface Builder Document" disable: "Use Autolayout"

In Xcode Interface Builder how do I control how the element behave when the view is resized?

In older Xcode I have a little window where I could mark braces and band things to control how a NSView behaves when its parent is resized. In the new Xcode that is missing and the controls are doing whatever they feel like.
Is there any way to get this control back? (current version: Version 4.3.2 (4E2002))
Starting with Xcode 4.3 when you create a Cocoa application project, the xib file uses auto layout. Auto layout replaces the size inspector's autosizing mask.
If you want to use the autosizing mask, the solution is to turn off auto layout. Select the xib file from the project navigator, open the file inspector, and deselect the Use Auto Layout checkbox.
Read Constraints Express Relationships Between Views to learn how views are constrained in Xcode 4. In fact, you probably want the entire Cocoa Auto Layout Guide.
Briefly, when you add a view to your view hierarchy, it comes with some constraints. Select the view in the and you'll see some blue lines that look a bit like I-beams -- these represent the constraints. Click on one of them and you can edit its properties in the attributes inspector. But how you should set the attributes probably won't make much sense until you've read about how constraints work in the document linked above.

Resources