have been getting into autolayouts recently and I'm stuck on what seems like a really trivial problem example. I have a view that I want to sit at the top of the screen, and take up half of the screen-height. Simple before autolayout - just tack it in place and tell it to expand vertically when the superview resizes.
Now, I can't for the life of me see how to do it. Here's what I get when I try to set this up:
https://i.stack.imgur.com/Lo413.png
The bottom space constraint is set to "equals 284", which is absolute and absolutely useless to me when I change to iPhone4 layout, as it keeps 284 points space at the bottom of the screen, and shrinks the view to no longer be half the size of the screen. And there's no way of setting that constraint to equal some fraction of any other view's height..
After struggling for a while, the only way I can think of doing this would be to introduce another view below this view, pin their heights equally, have them sit above and below each other and then set the second (bottom) view to be invisible.. which seems a bit ugly!
Am I missing something obvious?..
Storyboard solution where you can set exact ratio between any views:
https://i.stack.imgur.com/dHwom.png
Now:
https://i.stack.imgur.com/64SDU.png
PROFIT!!!
https://i.stack.imgur.com/8Im6S.png
P.S. Also note that this method works with views on different nesting levels and (obviously) applicable for width
P.P.S. sometimes it might be helpful to "reverse first and second item" of constraint or set reverse multiplier (for example 2 instead of 0.5) (but these methods are not helpful if you don't understand how views relate between each other).
This is now possible in IB as of [at least] Xcode 5.1.1. Although it took me sometime to figure out it is actually super simple:
First create a basic top alignment constraint (you will also need to setup bottom, left, and right constraints, like normal) . Then select the constraint and navigate to the Attribute inspector:
https://i.stack.imgur.com/OuxVA.png
Then you can adjust the multiplier. If you want it 50% of the super view leave it at 1
, since it is aligned per the super's center. This is also a great way to create views that are other percentages too (like 25% of super view)
https://i.stack.imgur.com/jDvj0.png
First Item
is View.Top
not View.Center Y
. Otherwise, yes it will just center it. You will also need to make sure other constraints are set properly to handle the view's other edges.
After a bit more time I've come up with the following.
I'm noting it as an answer but it's not very satisfying, since it assumes you can't actually do this in Interface Builder, but the correct constraint can be added in code afterwards as:
- (void) viewWillAppear:(BOOL)animated
{
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:upperview
attribute:NSLayoutAttributeHeight
relatedBy:0
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:.5
constant:0];
[self.view addConstraint:constraint];
}
Basically, it sets a multiplier of 0.5 against the height of self.view, acting on upperview. I had to set the priority of the bottom vertical space constraint in IB to lower than 1000 to avoid a bunch of runtime messages about breaking constraints as well.
So if anyone can show how to do this in Interface Builder, that would better answer my question, otherwise I guess this is as good as it gets (for now)???
Slightly easier and more straight forward than method than Fyodor Volchyok's answer. -Hold down the control button and click on the subview. -Still holding down on the command button, drag cursor to the superview then click on the superview. -Select "Aspect Ratio".
https://i.stack.imgur.com/zVcWY.png
https://i.stack.imgur.com/n7uPG.png
https://i.stack.imgur.com/nkHHM.png
https://i.stack.imgur.com/dDTLw.png
There i also another possibility in code in case you have 2 views that should both have the same height: just set the height of view2 to the height of view1 (the trick here is not setting the height of view1 explicitely).
[self.view addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:[topLayoutGuide]-0-[_view1]-0-[_view2(==_view1)]-0-[bottomLayoutGuide]"
options:0
metrics:nil
views:viewsDict]];
Swift version of Mete's answer:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
upperView.translatesAutoresizingMaskIntoConstraints = false
var constraint = NSLayoutConstraint(item: upperView,
attribute: NSLayoutAttribute.top,
relatedBy: NSLayoutRelation.equal,
toItem: self.view,
attribute: NSLayoutAttribute.top,
multiplier: 1,
constant: 0)
self.view.addConstraint(constraint)
constraint = NSLayoutConstraint(item: upperView,
attribute: NSLayoutAttribute.height,
relatedBy: NSLayoutRelation.equal,
toItem: self.view,
attribute: NSLayoutAttribute.height,
multiplier: 0.5,
constant: 0)
self.view.addConstraint(constraint)
constraint = NSLayoutConstraint(item: upperView,
attribute: NSLayoutAttribute.leading,
relatedBy: NSLayoutRelation.equal,
toItem: self.view,
attribute: NSLayoutAttribute.leading,
multiplier: 1,
constant: 0)
self.view.addConstraint(constraint)
constraint = NSLayoutConstraint(item: upperView,
attribute: NSLayoutAttribute.trailing,
relatedBy: NSLayoutRelation.equal,
toItem: self.view,
attribute: NSLayoutAttribute.trailing,
multiplier: 1,
constant: 0)
self.view.addConstraint(constraint)
}
Success story sharing