Autolayout - Make Height of View Relative to Half Superview Height

autolayout - make height of view relative to half superview height

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:

Demonstration of steps above

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)

Demonstration of second step above

How to setup a view with a half of screen height?

Try to change heightConstraint's constant value in viewDidLayoutSubviews method.

override func viewDidLayoutSubviews() {
heightConstraint.constant = self.view.frame.size.height / 2
}

In autolayout, how can I have view take up half of the screen, regardless of orientation?

The first half of the answer address the case in which we want to split the view evenly between view A (blue) and view B (red). The second half will address the case in which we want to have view A take up half the screen, but view B does not exist.

Step 1:

Sample Image

Set up blue's auto-layout constraints as pictured. Top, left, bottom of 0 to the superview. Right of 0 to the red view.

Step 2:

Sample Image

Set up the same, but mirrored, constraints for the red view.

If you've completed the first two steps correctly, you should have some auto-layout errors and warnings:

Sample Image

We need one more constraint to fix these errors/warnings and get what we need.

Step 3:

Sample Image

Hold control, click and drag from one view to the other and select "equal widths". Now our views will always maintain the same width. All of our auto layout warnings and errors disappear, and our views will always be half the screen no matter the orientation or device.

To add these constraints in code using VFL, we need the following constraints:

@"H:|[blueView(==redView)][redView]|"
@"V:|[blueView]|"
@"V:|[redView]|"

Now, suppose the case where we want a single view to take up half the screen, but we don't have a view for the other half. We can still do this with auto layout, but it's a slightly different set up. In this example, our view is blue, and its parent view is green.

Step 1:

Sample Image

This is similar to step 1 above, except we don't add a right side constraint (this will obviously vary if we want our view to take up a different half).

Step 2:

Sample Image

Like before, we want to assign an "equal widths" constraint. In this case, from our view to the parent view. Again, hold control and click drag from one to the other.

Sample Image

At this point, we have an auto layout warning. Auto layout wants our frame to match its parent's width. Clicking the warning and choosing "Update constraints" will put a hardcoded value in. We don't want this.

Step 3:

Sample Image

Select the view and go to its size inspector. Here, we'll be able to edit the constraints.

Click "Edit" next to the "Equal Width to:" constraint. We need to change the multiplier value.

Sample Image

We need to change the multiplier value to 2.

The constraint now changes to a "Proportional Width to:", and all of our auto layout warnings and errors disappear. Now our view will always take up exactly half of the super view.

To add these constraints in code, we can add some using VFL:

@"H:|[blueView]"
@"V:|[blueView]|"

But the proportional width constraint can't be added with VFL. We must add it as such:

NSLayoutConstraint *constraint =
[NSLayoutConstraint constraintWithItem:blueView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:2.0
constant:0.0];

Set up height constraint for superview based on child views

you do it by constraining the first label's top to self's top and then the last label's bottom to self's bottom. each of the labels in between have their top constrained to the previous label's bottom.

@interface SomeView: UIView
@end

@implementation SomeView

- (instancetype)init {
self = [super init];
if (!self)
return nil;

// create an array of random labels
NSArray <UILabel*> *labels = [self labelsWithRandomText:10];

// add each label to the view, setting it's top to the previous view's bottom
UIView *previousView = self;
for (UILabel *label in labels) {
[self addSubview:label];

// bound the left and right of the label to match the parent view
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label)]];

// if this is the first label being added, set its top to self's top
// otherwise set its top to the bottom of the previous view
NSLayoutAttribute previousAttribute = previousView == self ? NSLayoutAttributeTop : NSLayoutAttributeBottom;
[self addConstraint:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:previousView attribute:previousAttribute multiplier:1 constant:0]];

// update previous view
previousView = label;
}

// constrain self's bottom to the bottom of the last label
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:previousView attribute:NSLayoutAttributeBottom multiplier:1 constant:0]];

return self;
}

// create an array of labels w/ random color and background text
- (NSArray <UILabel *> *)labelsWithRandomText:(int)labelCount {
NSMutableArray <UILabel*> *labels = [NSMutableArray new];
for (int i = 0; i < labelCount; i++) {
UILabel *label = [UILabel new];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.numberOfLines = 0;
label.backgroundColor = [self randomColor];
label.text = [self randomString];
[labels addObject:label];
}

return labels;
}

// create random color
- (UIColor *)randomColor {
return [UIColor colorWithRed:(arc4random()%255)/255. green:(arc4random()%255)/255. blue:(arc4random()%255)/255. alpha:1];
}

// create random string
- (NSString *)randomString {
static NSArray <NSString*> *words;
static NSInteger wordCount;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
words = @[@"cat ", @"dog ", @"bird ", @"went ", @"home ", @"with ", @"under ", @"red ", @"blue ", @"green "];
wordCount = [words count];
});

NSMutableString *randomString = [NSMutableString new];

// create somewhere between 10-30 words
int randomWordCount = arc4random() % 20 + 10;
for (int i = 0; i < randomWordCount; i++) {
[randomString appendString:words[arc4random() % wordCount]];
}
return randomString;
}

@end

Set subview height relative to parent view in Storyboard

Add a height constraint whose multiplier value is 1/3 so the image view's height will be one third of its superview's height.

Sample Image

--

Here is how it looks with different device sizes:

Bad rendering on small screen    Bad rendering on small screen     Bad rendering on small screen    

How do I use auto layout to start a view in the half of its superview?

I don't think you can do this in Interface Builder, but this is pretty easy to do by creating the constraints in code.

Your first equation is exactly how I would express the constraint. The second equation might work, but it is weird to relate an origin to a width. They are different quantities. Instead, just pin the right of the innerView to the right of the outerView.

We use the attribute NSLayoutAttributeTrailing instead of NSLayoutAttributeRight, so your interface will properly flip when localized RTL.

// innerView.width = outerView.width * 0.5
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:innerView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:outerView
attribute:NSLayoutAttributeWidth
multiplier:0.5
constant:0];

// innerView.trailing = outerView.trailing
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:innerView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:outerView
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0];

[outerView addConstraints:@[widthConstraint, rightConstraint]];


Related Topics



Leave a reply



Submit