NSLayoutConstraint in a Loop FOR - ios

I'm trying to create UILabel through a for loop that gets its NSInteger from an NSArray. The cycle works properly but I can not see all the vertices one below the other. I'm definitely wrong something with constraint. Can you help me?
Based on this code I posted how can I fix the NSLayoutConstraint problem within a for loop?
NSInteger max = [[_yValueArray valueForKeyPath:#"#max.self"] integerValue];
NSInteger min = [[_yValueArray valueForKeyPath:#"#min.self"] integerValue];
for (NSInteger value = max; value >= min; value -=1) {
UILabel *valueLabel = [[UILabel alloc] init];
valueLabel.textColor = [UIColor lightGrayColor];
valueLabel.backgroundColor = [UIColor redColor];
valueLabel.textAlignment = NSTextAlignmentLeft;
valueLabel.font = [UIFont defaultAppFontWithSize:10];
valueLabel.translatesAutoresizingMaskIntoConstraints = NO;
valueLabel.text = [self yValueString:value];
valueLabel.tag = value;
[yAxisView addSubview:valueLabel];
[yAxisView addConstraint:[NSLayoutConstraint constraintWithItem:valueLabel attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:valueLine attribute:NSLayoutAttributeLeft multiplier:1 constant:-2]];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:valueLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:yAxisView attribute:NSLayoutAttributeTop multiplier:1 constant:0];
[yAxisView addConstraint:topConstraint];
NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:valueLabel attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:valueLine attribute:NSLayoutAttributeHeight multiplier:1 constant:10];
[yAxisView addConstraint: height];
// topConstraint.constant += height.constant;
}
What I'm trying to get is a bar graph like this ... At this time I wanted to get the result of the Y axis you see in the image ...

I'm gathering that the question is labeling the left axis vertically.
If your goal is to add labels to the left edge, you can set the centerY constraint as a multiple of the centerY of its superview. The only trick is that it doesn't like a 0 for the multiplier for centerY, so for that top one, I'd just set the centerY to be equal to the top of its superview. Thus:
NSInteger max = 10;
for (NSInteger i = 0; i <= max; i++) {
UILabel *label = [[UILabel alloc] init];
label.translatesAutoresizingMaskIntoConstraints = false;
label.text = [NSString stringWithFormat:#"%ld", (long)i];
[self.chartDataView addSubview:label];
CGFloat multiplier = (CGFloat)(max - i) * 2.0 / (CGFloat)max;
[self.chartDataView addConstraint:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.chartDataView attribute:NSLayoutAttributeLeft multiplier:1 constant:-5]];
if (multiplier == 0) {
[self.chartDataView addConstraint:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.chartDataView attribute:NSLayoutAttributeTop multiplier:1 constant:0]];
} else {
[self.chartDataView addConstraint:[NSLayoutConstraint constraintWithItem:label attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.chartDataView attribute:NSLayoutAttributeCenterY multiplier:multiplier constant:0]];
}
}
Yields:
Clearly, I'm not drawing any chart, but this shows how, given a chart graph area, you can use the multiplier to dictate where the labels go.

Related

Unable to add textfields vertically in iOS?

I have added some text fields through story board vertically.Below them i want to add more text fields programatically but it is always adding only one text field.
Below is the code used
int i;
self.main_view.translatesAutoresizingMaskIntoConstraints = NO;
self.scroll_view.translatesAutoresizingMaskIntoConstraints = NO;
for (i=0; i<[arr_customEdtTxt count]; i++)
{
JVFloatLabeledTextField *tf = [[JVFloatLabeledTextField alloc] initWithFrame:CGRectMake(25, y, 270, 27)];
tf.textColor = [UIColor blackColor];
tf.font = [UIFont fontWithName:#"Helvetica" size:14];
CustomEditText *custom=[arr_customEdtTxt objectAtIndex:i];
tf.placeholder=custom.field_name;
tf.textAlignment=NSTextAlignmentLeft;
previousTextfield=tf;
//add bottom border
[self addBorder:tf];
tf.translatesAutoresizingMaskIntoConstraints = NO;
[self.main_view addSubview:tf];
y=y+27;
[self.main_view addConstraint:[NSLayoutConstraint constraintWithItem:tf attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.main_view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0] ];
[self.main_view addConstraint:[ NSLayoutConstraint constraintWithItem:tf
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeHeight
multiplier:1.0
constant:27.0]];
[self.main_view addConstraint:[ NSLayoutConstraint constraintWithItem:tf
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.txt_email
attribute:NSLayoutAttributeWidth
multiplier:1.0
constant:0]];
if(i==0)
{
[self.main_view addConstraint:[NSLayoutConstraint constraintWithItem:tf attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.txt_exprience attribute:NSLayoutAttributeBottom multiplier:1 constant:15.0f]];
}
else
{
[self.main_view addConstraint:[NSLayoutConstraint constraintWithItem:tf attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:previousTextfield attribute:NSLayoutAttributeBottom multiplier:1 constant:15.0f]];
}
[arr_tf addObject:tf];
}
[self.main_view layoutIfNeeded];
[self setDatatoFields];
I am getting constraint error i want to add more text fields below the current text fields.Please tell how can i add more and more text fileds below
It looks like previousTextfield and tf refer to the same textfield in this line:
[self.main_view addConstraint:[NSLayoutConstraint constraintWithItem:tf attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:previousTextfield attribute:NSLayoutAttributeBottom multiplier:1 constant:15.0f]];
Also I noticed that at the end you add the textField to arr_tf but you also have arr_customEdtTxt depending on which one is your array of textFields you should change previousTextfield = tf with:
if(i > 0){
//Change arr_tf for arr_customEdtTxt if that is your array
previousTextfield = [arr_tf objectAtIndex:i-1];
}

How to change or update NSLayoutConstraint programmatically

I have implemented AutoLayout programmatically using the Code :
- (void)addConstraintWithListNavigationViewController:(UIView *)listViewNavigation y:(CGFloat)y height:(CGFloat)height
{
//WIDTH_ListTableView = 0.4
//set x = 0;
NSLayoutConstraint *constraintToAnimate1 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:0.00
constant:0];
[self.view addConstraint:constraintToAnimate1];
//set y = y;
NSLayoutConstraint *constraintToAnimate2 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:0.00
constant:y];
[self.view addConstraint:constraintToAnimate2];
//set Width = self.view.frame.size.width*0.4
NSLayoutConstraint *constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1-WIDTH_ListTableView
constant:0.0];
[self.view addConstraint:constraintToAnimate3];
//Set height = height
NSLayoutConstraint *constraintToAnimate4 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.00
constant:height];
[self.view addConstraint:constraintToAnimate4];
}
And this works perfect, but every-time this ViewController receives a Notification, it will run:
[self.view layoutIfNeeded];
But I want to set the width of listViewNavigation according a boolean variable connected.
if(connected){
listViewNavigation.view.frame.size.width = 0.4 * self.view.frame.size.width;
}
else{
listViewNavigation.view.frame.size.width = 0.6 * self.view.frame.size.width;
}
But i do not know how can I update the NSLayoutConstraint :
NSLayoutConstraint *constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:PreView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1 - WIDTH_ListTableView
constant:0.0];
[self.view addConstraint:constraintToAnimate3];
when this ViewController receive the notification.
I think you have 2 options.
Option 1
Keep a property
#property (strong,nonatomic)NSLayoutConstraint *constraintToAnimate3;
Then use this property to
self.constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:PreView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:1
constant:-1 * 0.4 * self.view.frame.size.width];
[self.view addConstraint:self.constraintToAnimate3];
When you want to change
if(connected){
self.constraintToAnimate3.constant = -1 *0.6 * self.view.frame.size.width;
}
else{
self.constraintToAnimate3.constant = -1 *0.4 * self.view.frame.size.width;
}
[UIView animateWithDuration:yourduration animations:^{
[self.view layoutIfNeeded];
}];
Option 2
Set an identifier of constraintToAnimate3
constraintToAnimate3.identifier = #"1234"
Then search to get the constraint
NSLayoutConstraint * constraint3 = nil;
NSArray * constraints = self.view.constraints;
for (NSLayoutConstraint * constraint in constraints) {
if ([constraint.identifier isEqualToString:#"1234"]) {
constraint3 = constraint;
break;
}
}
Then change the constant as shown in Option1
Update:
If use constant in the code I post
PreView.frame.size.with = self.view.size.width * multiplier + constant
OK, I figure out.
[self.view removeConstraint:self.constraintOld];
[self.view addConstraint:self.constraintNew];
[UIView animateWithDuration:time animations:^{
[self.view layoutIfNeeded];
}];
It's essential that you don't just add the constraints to your view, but that you also remember them.
It's easiest to change a constraint if you only need to change its constant - the constant is the only part of a constraint that can be changed later repeatedly. To do that, you need to store the constraint on its own.
Otherwise you need to remove old constraints and add new ones. Since you usually have more than one constraint, store arrays with sets of constraints that may need to be replaced, then update the whole array. You can also use the activateConstraints and deactivateConstraints methods.

Xcode Unable to change second childViewController's frame

I have a MenuViewController and inside this viewController I have two childViewControllers which first one is on left part and second one is on the right side.
VIEW_WIDTH = self.view.frame.size.width;
WIDTH_ListTableView = 0.4;
ListViewController *listViewController = [[ListViewController alloc] init];
ListNavigationViewController *listViewNavigation = [[ListNavigationViewController alloc] initWithRootViewController:listViewController];
[self addChildViewController:listViewNavigation];
[self.view insertSubview:listViewNavigation.view belowSubview:self.searchBarView.view];
[listViewNavigation didMoveToParentViewController:self];
listViewNavigation.view.frame = CGRectMake(0,
y,
VIEW_WIDTH*WIDTH_ListTableView,
height);
PreViewViewController *readViewController = [[PreViewViewController alloc] init];
[self addChildViewController:readViewController];
[self.view insertSubview:readViewController.view belowSubview:listViewNavigation.view];
[readViewController didMoveToParentViewController:self];
readViewController.view.frame = CGRectMake(listViewNavigation.view.frame.origin.x + listViewNavigation.view.frame.size.width,
listViewNavigation.view.frame.origin.y,
VIEW_WIDTH - listViewNavigation.view.frame.size.width,
listViewNavigation.view.frame.size.height);
But I cannot change the frame of readViewController and its width and height are always (768.0, 1024.0).
I added constraint to listViewNavigation, but listViewNavigation.view.y = 0
- (void)addConstraintWithListNavigationViewController:(UIView *)listViewNavigation y:(CGFloat)y height:(CGFloat)height
{
//set x = 0;
NSLayoutConstraint *constraintToAnimate1 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeft
multiplier:0.00
constant:0];
[self.view addConstraint:constraintToAnimate1];
//set y = y;
NSLayoutConstraint *constraintToAnimate2 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:0.00
constant:y];
[self.view addConstraint:constraintToAnimate2];
//set Width = self.view.frame.size.width*0.4
NSLayoutConstraint *constraintToAnimate3 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:WIDTH_ListTableView
constant:0.0];
[self.view addConstraint:constraintToAnimate3];
//Set height = height
NSLayoutConstraint *constraintToAnimate4 = [NSLayoutConstraint constraintWithItem:listViewNavigation
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.00
constant:height];
[self.view addConstraint:constraintToAnimate4];
}
this is because you are have auto layout enabled. Try to update the constraints after changing frame by using the function [readViewController.view setTranslatesAutoresizingMaskIntoConstraints:YES]

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.

ios AutoLayout issue for flexible width?

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

Resources