ios AutoLayout issue for flexible width? - ios

I think this is an issue of autolayout.
I create a view, and create some subviews in it.
The content view contains the subviews, and the subviews lays all in one line.
I think I didn't do something wrong, but the content view 's frame always incorrect.
like this:
2013-08-29 14:13:34.688 AutoLayoutBugTest[4658:c07] pV_content.frame {{0, 208}, {319, 44}}
The content view's width is 319 but not 320, change the 'cnt' param in viewDidLoad function, the frame may worse.
code like this:
#interface ViewController ()
#property (nonatomic, strong) UIView *pV_content;
#property (nonatomic, strong) NSMutableArray *Arr_views;
#end
#implementation ViewController
- (void)removeConstraintForCustomView:(UIView *)customView
fromView:(UIView *)superView
{
NSMutableArray *pArr_constraint = [NSMutableArray array];
for (NSLayoutConstraint *constraint in superView.constraints) {
if ([constraint.firstItem isEqual:customView]) {
[pArr_constraint addObject:constraint];
}
}
[superView removeConstraints:pArr_constraint];
pArr_constraint = nil;
}
- (void)constraintCustomView:(UIView *)customView
matchWidthOfView:(UIView *)superView
withHeight:(CGFloat)height
{
[self removeConstraintForCustomView:customView fromView:superView];
customView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint_y = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeCenterY
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_y];
NSLayoutConstraint *constraint_height = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeHeight
multiplier:0.f
constant:height];
[superView addConstraint:constraint_height];
NSLayoutConstraint *constraint_left = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeLeft
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_left];
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_width];
}
- (void)constraintCustomView:(UIView *)customView
matchWidthPercentOfView:(UIView *)superView
boxCount:(int)boxCount
boxIndex:(int)boxIndex
{
[self removeConstraintForCustomView:customView fromView:superView];
customView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *constraint_top = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:customView.frame.origin.y];
[superView addConstraint:constraint_top];
constraint_top.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_height = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeHeight
multiplier:0.f
constant:customView.frame.size.height];
[superView addConstraint:constraint_height];
constraint_height.priority = UILayoutPriorityFittingSizeLevel;
if (boxCount == 1) {
NSLayoutConstraint *constraint_percent_x = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeCenterX
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_percent_x];
constraint_percent_x.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:1.f
constant:-4.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
else {
if (boxIndex == 0) {
NSLayoutConstraint *constraint_left = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeLeft
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_left];
constraint_left.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:(2.f / (CGFloat)(2 * boxCount + 1))
constant:-2.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
else if (boxIndex == boxCount - 1) {
NSLayoutConstraint *constraint_right = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeRight
multiplier:1.f
constant:0.f];
[superView addConstraint:constraint_right];
constraint_right.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:(2.f / (CGFloat)(2 * boxCount + 1))
constant:-2.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
else {
NSLayoutConstraint *constraint_percent_x = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeCenterX
multiplier:(((CGFloat)(2 * boxIndex + 1)) / (CGFloat)boxCount)
constant:0.f];
[superView addConstraint:constraint_percent_x];
constraint_percent_x.priority = UILayoutPriorityFittingSizeLevel;
NSLayoutConstraint *constraint_width = [NSLayoutConstraint constraintWithItem:customView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:superView
attribute:NSLayoutAttributeWidth
multiplier:(2.f / (CGFloat)(2 * boxCount + 1))
constant:-2.f];
[superView addConstraint:constraint_width];
constraint_width.priority = UILayoutPriorityFittingSizeLevel;
}
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
self.pV_content = [[UIView alloc] initWithFrame:CGRectMake(0.f,
0.f,
self.view.frame.size.width,
44.f)];
self.pV_content.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:self.pV_content];
[self constraintCustomView:self.pV_content
matchWidthOfView:self.view
withHeight:44.f];
int cnt = 5;
for (int i = 0; i < cnt; i++) {
UIView *pV_sub = [[UIView alloc] initWithFrame:CGRectMake(0.f,
5.f,
30.f,
35.f)];
pV_sub.backgroundColor = [UIColor redColor];
[self.pV_content addSubview:pV_sub];
[self constraintCustomView:pV_sub
matchWidthPercentOfView:self.pV_content
boxCount:cnt
boxIndex:i];
}
}
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
NSLog(#"pV_content.frame %#", NSStringFromCGRect(self.pV_content.frame));
}
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
#end

From guide:
Constraints are of the form "view1.attr1 view2.attr2 * multiplier + constant". If the constraint you wish to express does not have a second view and attribute, use nil and NSLayoutAttributeNotAnAttribute.
And secondary: Try use
constraintsWithVisualFormat:options:metrics:views:
For example if you have a view testView:
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[testView]|" options:0 metrics:0 views:#{#"testView":self.testView}]];
in constraintsWithVisualFormat method you can set priority and variants like:#"H:|-(0#100)-[testView(100)]-(0#100)-|". This testView have hight priority, because priority parameter not set, but 2 constraints from left and right size to superview have priority 100, and your view testView not change self frame.
You can set format like this: [testView(50,100)] in this your code means: "testView widht can be 50 points or 100.
Read this guide

Related

iOS Autolayout relative to the sibling UIViews programatically

I am trying to add 3 custom views (redView, greenView, yellowView) inside a container view (C1) such that all the custom views (redView, greenView, yellowView) are below each other using Auto layout constraints programatically. I want the container view (C1) to get the same size as the size of it subview, so the output should be like this.
The red, green and yellow views are just to show the expected result. Actually the custom view i have is like this.
I am using Auto Layout to do this. Here is my code to do this. RatingsSingleView is my custom view which are shown in the above image.
#interface ViewController ()
#property (weak, nonatomic) IBOutlet UIView *ratingsContainerView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView *previousTopView = self.ratingsContainerView;
for(int i = 0; i < 3; ++i) {
RatingsSingleView *view = [[RatingsSingleView alloc] init];
view.translatesAutoresizingMaskIntoConstraints = NO;
[self.ratingsContainerView addSubview:view];
NSLayoutConstraint *topConstraint = nil;
if(i == 0) {
// Making the first subview top aligned to the container View top
topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:previousTopView attribute:NSLayoutAttributeTop multiplier:1.0 constant:10.0];
} else{
// Making the second and third subview top aligned to the view above it
topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:previousTopView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:10.0];
}
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.ratingsContainerView attribute:NSLayoutAttributeLeft multiplier:1.0 constant:10.0];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.ratingsContainerView attribute:NSLayoutAttributeRight multiplier:1.0 constant:10.0];
[self.ratingsContainerView addConstraint:topConstraint];
[self.ratingsContainerView addConstraint:leftConstraint];
[self.ratingsContainerView addConstraint:rightConstraint];
if(i == 2) {
// Adding last subview bottom to the container View bottom
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.ratingsContainerView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-10.0];
[self.ratingsContainerView addConstraint:bottomConstraint];
}
previousTopView = view;
}
}
#end
So the issue is i am not getting the expected result. I am pinned the container view to the left and right edges and set its height to 0 in the storyboard. once i run the above code i am getting the following result.
Can some body could guide me what i am doing wrong here. thanks
You have given some wrong constraints and I've corrected it try this...
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView *previousTopView = self.ratingsContainerView;
for(int i = 0; i < 3; ++i) {
RatingsSingleView *view = [[RatingsSingleView alloc] init];
view.translatesAutoresizingMaskIntoConstraints = NO;
[self.ratingsContainerView addSubview:view];
NSLayoutConstraint *topConstraint = nil;
if(i == 0) {
// Making the first subview top aligned to the container View top
topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:previousTopView attribute:NSLayoutAttributeTop multiplier:1.0 constant:10.0];
} else{
// Making the second and third subview top aligned to the view above it
topConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:previousTopView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:10.0];
}
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.ratingsContainerView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:10.0];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:self.ratingsContainerView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:10.0];
[self.ratingsContainerView addConstraint:topConstraint];
[self.ratingsContainerView addConstraint:leftConstraint];
[self.ratingsContainerView addConstraint:rightConstraint];
if(i == 2) {
// Adding last subview bottom to the container View bottom
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:self.ratingsContainerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:10.0];
[self.ratingsContainerView addConstraint:bottomConstraint];
}
previousTopView = view;
}

Instance variable used while 'self' is not set to the result of [(super or self) init…]

My Code :
- (instancetype)initWithSender:(UIView*)sender withSuperView:(UIView*)superView withItems:(NSMutableArray*)items
{
self = [CustomDropdownView loadInstanceFromNibWithiPad:NO];
if (self) {
self.frame = CGRectZero;
[self.layer setBorderColor:[UIColor lightGrayColor].CGColor];
[self.layer setBorderWidth:1.0];
CGRect positionInSuper = [superView convertRect:sender.frame fromView:sender.superview];
float height = superView.frame.size.height - positionInSuper.origin.y;
if (height > 200.0) {
// height = 200.0;
}
[superView addSubview:self];
self.translatesAutoresizingMaskIntoConstraints = NO;
self.constLeading = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:positionInSuper.origin.x];
self.constTop = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:superView attribute:NSLayoutAttributeTop multiplier:1.0 constant:positionInSuper.origin.y + sender.frame.size.height];
self.constWidth = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:sender.frame.size.width];
self.constHeight = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0];
[superView addConstraints:#[self.constLeading, self.constTop]];
[self addConstraints:#[self.constWidth, self.constHeight]];
[self layoutIfNeeded];
self.arrItems = [[NSMutableArray alloc]initWithArray:items];
[self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([DropDownTableViewCell class]) bundle:nil] forCellReuseIdentifier:NSStringFromClass([DropDownTableViewCell class])];
[self.tableView reloadData];
}
return self;
}
The first line
self = [CustomDropdownView loadInstanceFromNibWithiPad:NO];
is very problematic. You should only assign the result of another init method, usually [super init]. Change this to a class method.
By the way, that's what the error message says.

How to scroll the scroll view using auto-layouts "constraint with item" formate in ios?

Here I am adding one scrollview programmatically on Viewcontroller using "constraint with item" format and inside that scrollview I have added one UIlabel. So everything is good.
But here I have given "NSLayoutAttributeBottom" between scrollview and label is "-200" that means scrollview is scrolling up to "200" range on viewcontroller controller, but according to my code it is not scrolling.
As per drag and drop procedure it's ok, I have checked, it's working fine.
Why it's not possible to do it programmatically?
my code is below:-
#import "ViewController4.h"
#interface ViewController4 ()
{
UIScrollView * scrollView;
UILabel * label;
}
#end
#implementation ViewController4
- (void)viewDidLoad {
[super viewDidLoad];
scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = [UIColor lightGrayColor];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
label = [[UILabel alloc] init];
label.backgroundColor = [UIColor redColor];
label.text = #"Hello World1";
label.textAlignment = NSTextAlignmentCenter;
label.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:label];
//Applying autolayouts for scrollview
NSLayoutConstraint * constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem: self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
constraint1 = [NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint1];
//Applying autolayouts for label
NSLayoutConstraint * constraint2 = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem: scrollView attribute:NSLayoutAttributeTop multiplier:1.0f constant:100.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:10.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:-10.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:30.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-100.0f];
[scrollView addConstraint:constraint2];
}
In above code i have clearly given NSLayoutAttributeBottom space is "-200" but scroollview is not scrolling what did i do here wrong please help me some and how can i scroll this scrollview

Add a number of buttons to view with X,Y,padding constraints using autolayout programatically

Let say I have a N numbers of buttons..
//---listOfServicesToDisplay is DYNAMIC
NSMutableArray * arrayOfButtons = [NSMutableArray array];
for (int i=0; i<[listOfServicesToDisplay count]; i++) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[arrayOfButtons addObject:button];
}
I want to add arrayOfButtons to my superView with a constraints of:
Center Y Alignment (Vertical)
Center X Alignment (Horizontal)
Leading and Trailing with 50 padding. H:|50-[BUTTON]50-|
Top and Bottom with padding 1
For the most Top/Bottom button its padding would be dynamic
If I do it on INTERFACE BUILDER It would be look like this..(hence that I NEED TO DO IT PROGRAMATICALLY)
I think this works, it sets up a wrapperView around the buttons, aligns the buttons inside this view and centers the wrapperView inside its superview.
UIView *buttonView = [UIView new];
[buttonView setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.view addSubview:buttonView];
NSLayoutConstraint *horizontal = [NSLayoutConstraint constraintWithItem:buttonView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:buttonView.superview
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0.0];
NSLayoutConstraint *vertical = [NSLayoutConstraint constraintWithItem:buttonView
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:buttonView.superview
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0];
NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:buttonView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:buttonView.superview
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:-100];
// height will have to wait until we know what the buttons are up to
[buttonView.superview addConstraints:#[horizontal, vertical,width]];
CGFloat buttonHeight = 50;
CGFloat buttonSpace = 10;
NSInteger numberOfButtons = [buttons count]; // buttons = your array of buttons
for (NSInteger index = 0; index < numberOfButtons; index++) {
UIButton *button = [buttons objectAtIndex:index];
[buttonView addSubview:button];
NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:buttonView
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:Nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:buttonHeight];
NSLayoutConstraint *horizontal = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:buttonView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
[buttonView addConstraints:#[ width, height, horizontal]];
// a bit clumsy here, due to the first button
if (index == 0) {
NSLayoutConstraint *vertical = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:button.superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0];
[button.superview addConstraint:vertical];
} else{
UIButton *formerButton = [buttons objectAtIndex:index-1];
NSLayoutConstraint *vertical = [NSLayoutConstraint constraintWithItem:button
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:formerButton
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:buttonSpace];
[button.superview addConstraint:vertical];
}
}
UIButton *lastButton = [buttons lastObject];
CGFloat viewHeight = (buttonSpace + buttonHeight) * [buttons count];
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:buttonView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:viewHeight];
[buttonView addConstraint:height];
Now, I haven't attempted to clean this up at all and you'd certainly don't want to have this all in one block, but the concept is sound and you should be able to achieve what you want. Personally I often use a separate class to handle constraints to avoid duplication of code.

Implement child UIView with fixed aspect ratio to aspect fit

I have some issue with autolayout.
We have ViewController with root view and child view.
Child view have fixed aspect ratio.
I need to fit child view in parent while rotation.
Also chid view should be centered.
Like on a picture:
I have this code:
- (void)viewDidLoad
{
[super viewDidLoad];
UIView * v = [UIView new];
v.backgroundColor = [UIColor redColor];
v.translatesAutoresizingMaskIntoConstraints = NO;
v.tag = 100;
[self.view addSubview:v];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[v]|"
options:0
metrics:nil
views:#{#"v":v}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[v]|"
options:0
metrics:nil
views:#{#"v":v}]];
for (NSLayoutConstraint *c in self.view.constraints) {
[c setPriority:800];
}
NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:v
attribute:NSLayoutAttributeWidth
multiplier:0.8
constant:0.];
[c setPriority:1000];
[v addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
}
And it's not working, it's shrinks outside superview in landscape.
I've made it work with the following constraints:
- (void)viewDidLoad
{
[super viewDidLoad];
UIView * v = [UIView new];
v.backgroundColor = [UIColor redColor];
v.translatesAutoresizingMaskIntoConstraints = NO;
v.tag = 100;
[self.view addSubview:v];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|-(>=0)-[v]-(>=0)-|"
options:0
metrics:nil
views:#{#"v":v}]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|-(>=0)-[v]-(>=0)-|"
options:0
metrics:nil
views:#{#"v":v}]];
NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0];
[c setPriority:800];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:0];
[c setPriority:800];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:v
attribute:NSLayoutAttributeWidth
multiplier:0.8
constant:0.];
[c setPriority:1000];
[v addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
c = [NSLayoutConstraint constraintWithItem:v
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1
constant:0.];
[c setPriority:1000];
[self.view addConstraint:c];
}
Screenshots:

Resources