Flexible height with dynamic layout in Interface Builder - xcode

I'm new to the Dynamic Layout concept introduced in Cocoa applications with Lion 10.7.
I've been playing with some examples and almost all works as I expect. But, there is one thing I've been unable to get: Flexible Height in some elements.
I have one NSTextField element where I can set properly the following constraints:
Leading to trailing -> To keep it "near" to left and right border resizing its width.
Vertical space -> To keep it "near" to the previous vertical element.
I also set:
Vertical space -> To keep it "near" to the bottom border.
Height >= x -> With the previous one, to make its height "flexible" and adjustable to the view's height when resized.
When I test it, it works in the "horizontal axis" (location and size) but it doesn't allow me to resize the window's height (it's fixed).
If I delete the "Vertical space" constraint that attaches the NSInputText to the view's bottom, I can resize the window but the NSInpuntText's height remains unchanged.
Another annoying thing is that the "default" height constraint for the NSInputText (that on "pink" color) can't be deleted or modified. Whenever I do that a new one is created.
Any ideas?
Thanks.
UPDATE
If I use a "Text View" (NSScrollView with a NSTextField inside) instead of a "plain" NSTextField I'm able to create the behavior I want with any problem.

Related

How to make an item full width in auto layout constraint?

I'm trying to make a button full width in ios 9 storyboards, and am trying to create a width auto constraint, but the width constraint only seems to take an exact static number. How do I make the item go full width.
Additionally if I wanted say an imageview to be full height and adjustable width to maintain it's aspect ratio - or a size to fit fill, how would I do that with the auto layout constraints in the storyboard.
Should I be doing this programmatically in the view controller?
For the button:
In storyboard drag the left and right sides of the button to make it full width. Make sure the button is selected and add a pin constraint to the left and right (if you've dragged it full width the pin constraint should be equal to -20)
For the imageView:
The full height constraint is done almost exactly the same, although this time you need to drag the top and bottom to the top and bottom edges of the view controller and pin the top and bottom to their respective Layout guide.
You can make the image full screen in the view controller (pin top, bottom, left & right) and then edit the aspect ratio of the image in the Attributes inspector when the imageView is selected:
Hope that helps!

Xcode Autolayout - Setting UIButton Width equal to view width

I have a view with one UIButton with width equal to superview width. It renders correctly for iPhone 4s,5s but for 6+ it renders as shown below. I have tried adding constraints "trailing space to" "leading space to" to make it end to end but its not working and being new to layout I am not able to figure out where I am going wrong. Any suggestion is appreciated.
There are for things you have to work out with when you use autolayout...i.e.
x position of object
Y position of object
Height of Object
Width of object
here is the image for your button constraints and how it works...
At the first stage where i pinned leading space,trailing space and height i.e gives button height, width and x position....
But still i need Y position... so i gave Horizontal and vertical center constraints....
instead of this you can use top space constrain or only use vertical constraint instead of both Horizontal and vertical center constraints for Y position....
and the output screen is
In your "Add new constraints" popup do following:
Disable "Constrain to margins" checkbox
Add left and right constraints, set constants to 0.
Add height constraint.
Click "Add 3 constraints"
That's it!

NSScrollView with auto layout not resizing until first manual window resize

I've got an OSX Cocoa app that has been built programatically (i.e., not with a NIB/XIB), which I'm trying to lay out using auto layout - but I'm getting some odd behaviour when the window first displays.
My main content is an NSView that holds has a collection of 100 NSButtons as subviews, laid out vertically. The buttons are all constrained relative to the NSView and each other; both the NSView and all the NSButtons have translatesAutoresizingMaskIntoConstraints=NO set. I believe the code for the content view is good (i.e., no ambiguous layouts, etc), because if I set the main window's contentView to the NSView, the buttons display as expected.
However, if I set the main window's contentView to be an NSScrollView, and set the documentView of the NSScrollView to be the NSView, I get display problems.
On first display, I get a blank window - no scroll bars, nothing:
The NSScrollView has translatesAutoresizingMaskIntoConstraints=NO. For debug purposes, I've also set the background colour of the NSScrollView to blue so that I can confirm what is being laid out where - but there's no blue shown anywhere.
But, as soon as I resize the window, the layout kicks in, and I get an NSScrollView the full size of the main window, with blue background, and scrollbars as expected:
I've read some references that suggest the problem is the lack of constraints on the clipView that is part of the NSScrollView. On that basis, I've tried setting up constraints binding [NSScrollView contentView] to [NSScrollView documentView] in the vertical and horizontal directions (with constant 0, multiplier 1, on the left, right, top and bottom). When I do this, the NSScrollView is now visible on first display, but it's the wrong size. The scroll doesn't scroll the full height of the internal content - the scrollable content scrolls as if it is the same size as the visible window. Lastly, the content overlaps the titlebar of the window:
Again, as soon as I resize the window, the constraints kick in, and the window displays as I'd expect (see the previous screenshot). So, I take it the extra constraints don't hurt, but they don't seem to be adding anything, either.
Further confusing matters - if I leave the buttons off altogether, and just use an empty NSView with no subviews as the content view, I get a full window of blue on startup, as I'd expect.
So - what's going on here? It feels like I'm missing a call to force the evaluation of constraints on the buttons; is that the case, or is something else going on here?
For those interested - here's my sample code. It's not Objective C - it's Python - but the language binding can convert Python method names into Objective C messages; the mapping to native ObjectiveC API should be obvious:
app = NSApplication.sharedApplication()
app.setActivationPolicy_(NSApplicationActivationPolicyRegular)
main_window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
NSMakeRect(100, 100, 640, 480),
NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | NSMiniaturizableWindowMask,
NSBackingStoreBuffered,
False)
scrollview = NSScrollView.alloc().init()
scrollview.setHasVerticalScroller_(True)
scrollview.setHasHorizontalScroller_(True)
scrollview.setAutohidesScrollers_(True)
scrollview.setBorderType_(NSNoBorder)
scrollview.setTranslatesAutoresizingMaskIntoConstraints_(False)
scrollview.backgroundColor = NSColor.blueColor()
container = NSView.alloc().init()
container.setTranslatesAutoresizingMaskIntoConstraints_(False)
buttons = [
NSButton.alloc().init()
for b in range(0, 100)
]
for i, button in enumerate(buttons):
button.setBezelStyle_(NSRoundedBezelStyle)
button.setButtonType_(NSMomentaryPushInButton)
button.setTitle_(get_NSString('Button %s' % i))
button.setTranslatesAutoresizingMaskIntoConstraints_(False)
container.addSubview_(button)
if i == 0:
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeTop,
NSLayoutRelationEqual,
container, NSLayoutAttributeTop,
1, 50,
))
else:
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeBottom,
NSLayoutRelationEqual,
buttons[i-1], NSLayoutAttributeBottom,
1, 50,
))
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeLeft,
NSLayoutRelationEqual,
container, NSLayoutAttributeLeft,
1, 50,
))
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
button, NSLayoutAttributeRight,
NSLayoutRelationEqual,
container, NSLayoutAttributeRight,
1, -50,
))
container.addConstraint_(NSLayoutConstraint.constraintWithItem_attribute_relatedBy_toItem_attribute_multiplier_constant_(
buttons[-1], NSLayoutAttributeBottom,
NSLayoutRelationEqual,
container, NSLayoutAttributeBottom,
1, -50,
))
scrollview.setDocumentView_(container)
main_window.setContentView_(scrollview)
main_window.makeKeyAndOrderFront_(None)
app.activateIgnoringOtherApps_(True)
app.run()
I've worked out an answer - I'm not entirely happy with it, but it seems to work.
There are certain Cocoa widgets that don't deal well with autolayout - in particular, I've found problems with top level NSWindows and NSTabViewItems; I'm guessing other widgets might also be affected. Essentially, these are "container" widgets that have a top level "view" that must be set. If the "contained" widget is an NSScrollView (which itself will contain other widgets), the "container" widget has difficulty establishing a size for the "contained" scroll view.
The fix is to re-enable translatesAutoresizingMaskIntoConstraints for the view that will be used as the "contained" widget. In the example provided, the object scroll_view created on line 10 is the "contained" widget; the boolean value of the call to setTranslatesAutoresizingMaskIntoConstraints on line 15 should be True, not False.
These problems get better with more recent versions of OS/X - Mavericks doesn't have a problem with NSWindow, but it still has a problem with NSTabViewItem. However, it doesn't seem to do any damage to turn on translatesAutoresizingMaskIntoConstraints on newer versions of OS X; all you're losing it the theoretical purity of a 100% autolayout solution.
Look at Apple's 2012 developer conference videos about Auto Layout for information about using Auto Layout in code.
Simply use in Interface Builder or in code the approach I recorded in this video tutorial:
How to use NSScrollView with Auto Layout
This is the approach I used in this video:
Window -- set delegate and IBOutlet property
ScrollView -- fixed edges, no border, don't draw background
documentView -- fixed edges 0, then another trailing and bottom, clipView ≥ 0 #499 and clipView ≤ 0 #501 for both trailing and bottom constraints to documentView
label and text field in horizontal stack view, in vertical stack view
vertical stack view fixed edges default, then another bottom, bottom ≤ default #499 and ≥ default #750
horizontal stack view leading and trailing fixed 0
label and text field align Y center to horizontal stack view
text field top and bottom and trailing 2 #750, width ≥ 100, height ≥ 22
subsequent horizontal stack views leading and trailing fixed, align text field leadings
The real issue is that some of your controls are fixing the size of the view and thus for the window. For example, if you have only one view, say view1 inside your viewcontroller's view, and:
set leading/trailing/top/bottom to the main view and
view1.height = 300,
this will make your window size to be fixed to 300 and thus not resizeable.

How to ensure NSOutlineView inside a custom view renders full height (without scrolling)

I have a window with two custom views stacked on top of each other. I use auto layout constraints, as follows:
Top view leading, top, and trailing edges are tied to superview.
Bottom view leading, bottom, and trailing edges are tied to superview.
There is a fixed vertical space constraint between two views.
Bottom view has a fixed height constraint.
Top view has a it's compression resistance set to 751.
So far so good. The idea is that the bottom view height is fixed and as the window is resized, the top view height adjusts to compensate.
Both top and bottom views have other views/controllers loaded in, as appropriate. The bottom view ends up containing an outline view with a half-dozen entries. I would like that outline view not to scroll. In other words, I would like to automatically adjust my bottom view fixed height constraint to match the height of the outline view required for it not to scroll.
Ideally, I'd prefer to solve this with auto layout without having to write code. But, if that's stretching beyond what auto layout can do, code help would be appreciated as well.

Height constraint prevents resizing of NSWindow

I'm trying to get the hang of NSViewConstraints. I like them a lot; they make a lot more sense to me than the previous system.
I have a window, a 22 pixel-tall subview spanning the top of it, and a tabless, borderless NSTabView beneath it. The goal is to have the top subview never resize its height.
Without any constraints, auto formatting takes care of most of the work. The only trouble is resizing the window causes the upper subview to change its height. My seemingly logical response was to pin the height at 22. I left margin constraints alone, since the NSTabView was already handling resizing well.
By pinning the height of the upper subview, the window now refuses to resize vertically! I don't see any documentation anywhere saying this is expected or the logic behind it. I've messed with various constraint configurations to overcome it but nothing works.
Two questions:
Why is pinning the height of one subview freezing window height resizing? What is Xcode's logic?
What constraint setup will achieve the desired positioning?
I just tested creating a window as you describe, and pinning the height of the 22px view. This created one user constraint on the view for it's height.
However, it also created 2 constraints on the parent view (the window's content view), one for the Top Space to the 22px view, and a second for the Bottom Space to the 22px view. These constraints are what's preventing you from resizing your window. You should select the second constraint and delete it (but leave the first one in place as it's fine).

Resources