Xcode Unable to change second childViewController's frame - ios

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]

Related

Constraints programmatically with Objective C

I don't know what I'm doing wrong: I'm creating a UIView that occupies all the screen (it has already constraints) and then, programmatically I'm creating an UI Image View:
_panel = [[UIImageView alloc] initWithImage:[self loadImageForKey:#"registerPanel"]];
_panel.frame = CGRectMake(0, 0, 100, 100);
_panel.exclusiveTouch = YES;
_panel.userInteractionEnabled = YES,
[self.scrollView addSubview:_panel];
And here it comes the problem: I'm adding constraints to the panel I created but it crashes (I'm doing it on the ViewWillAppear):
NSLayoutConstraint *centreHorizontallyConstraint = [NSLayoutConstraint
constraintWithItem:_panel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
NSLayoutConstraint *centreVerticalConstraint = [NSLayoutConstraint
constraintWithItem:_panel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
[_panel addConstraint:centreHorizontallyConstraint];
[_panel addConstraint:centreVerticalConstraint];
Error message:
When added to a view, the constraint's items must be descendants of that view (or the view itself). This will crash if the constraint needs to be resolved before the view hierarchy is assembled. Break on -[UIView _viewHierarchyUnpreparedForConstraint:] to debug.
You can constrain a scrollView's subview to the scrollView's parent (self.view in this case), but that's probably not what you want.
Edit: For clarification, the reason you were getting the error was because you initialize your constraints:
toItem:self.view
and then you try to add them:
[_panel addConstraint:centreHorizontallyConstraint];
[_panel addConstraint:centreVerticalConstraint];
You want to add them to the toItem object:
[self.view addConstraint:centreHorizontallyConstraint];
[self.view addConstraint:centreVerticalConstraint];
Again, you probably don't want to center _panel in the main view, but this will compile and run:
#import "AddPanelScrollViewController.h" /// just default .h
#interface AddPanelScrollViewController ()
#property (strong, nonatomic) UIScrollView *scrollView;
#property (strong, nonatomic) UIImageView *panel;
#end
#implementation AddPanelScrollViewController
- (void)viewDidLoad {
[super viewDidLoad];
_scrollView = [UIScrollView new];
_scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:_scrollView];
[_scrollView.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:20.0].active = YES;
[_scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor constant:-20.0].active = YES;
[_scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:20.0].active = YES;
[_scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-20.0].active = YES;
_scrollView.backgroundColor = [UIColor blueColor];
_panel = [UIImageView new];
// required
_panel.translatesAutoresizingMaskIntoConstraints = NO;
[self.scrollView addSubview:_panel];
// frame will be ignored when using auto-layout / constraints
// _panel.frame = CGRectMake(0, 0, 100, 100);
_panel.exclusiveTouch = YES;
_panel.userInteractionEnabled = YES;
_panel.backgroundColor = [UIColor redColor];
// _panel needs width and height constraints
[_panel.widthAnchor constraintEqualToConstant:100.0].active = YES;
[_panel.heightAnchor constraintEqualToConstant:100.0].active = YES;
NSLayoutConstraint *centreHorizontallyConstraint = [NSLayoutConstraint
constraintWithItem:_panel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
NSLayoutConstraint *centreVerticalConstraint = [NSLayoutConstraint
constraintWithItem:_panel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0];
// if constraints are releated to "self.view" that's where they need to be added
[self.view addConstraint:centreHorizontallyConstraint];
[self.view addConstraint:centreVerticalConstraint];
}
First you can't create constraints between panel & self.view because there is no common parent , instead you want to create them with the scrollview
NSLayoutConstraint *centreHorizontallyConstraint = [NSLayoutConstraint
constraintWithItem:_panel
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
NSLayoutConstraint *centreVerticalConstraint = [NSLayoutConstraint
constraintWithItem:_panel
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.scrollView
attribute:NSLayoutAttributeCenterY
multiplier:1.0
constant:0];
[_scrollView addConstraint:centreHorizontallyConstraint];
[_scrollView addConstraint:centreVerticalConstraint];
Also both constraints are centerX , you need also width & height , or better top , leading , trailing and bottom to scrollView ,,, with width and height static or proportional to self.view
//
Also for any view you want to add constraints programmatically you must set
[self.scrollView setTranslatesAutoresizingMaskIntoConstraints: NO];
[self.panel setTranslatesAutoresizingMaskIntoConstraints: NO];

Program Subview's Vertical Spacing to Bottom Constraint

SecondViewController adds a UIView that contains a MKMapView as a subview inside an IBAction method:
if(_tagTwo == 4){
seg2_buttonImg = #"Maps.png";
UIImage *btnImage1 = [UIImage imageNamed:seg2_buttonImg];
[_left_button setImage:btnImage1 forState:UIControlStateNormal];
[_table removeFromSuperview];
[mapVC layoutMapView];
[self.view addSubview:mapVC.view];
return;
}
mapVC is created in ViewDidLoad with mapVC = [[CollectionMapViewController alloc] init];
Edit: new code for adding constraints, taken from #Reinier Melian:
#implementation CollectionMapViewController
#synthesize mapView;
- (void)viewDidLoad
{
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
//[segmentedControl setBackgroundColor:[UIColor whiteColor]];
//[segmentedControl setBackgroundColor:[UIColor leafletBrown]];
[segmentedControl setBackgroundColor:[UIColor leafletLightBrown]];
segmentedControl.layer.cornerRadius = 5;
}
self.mapView.translatesAutoresizingMaskIntoConstraints = NO;
NSArray * verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V:|[mapView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(self.mapView)];
NSArray * horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[mapView]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(self.mapView)];
//Add constraints to the Parent
[self.view addConstraints:verticalConstraints];
[self.view addConstraints:horizontalConstraints];
}
CollectionMapViewController.h:
#interface SecondViewController : UIViewController <NSFetchedResultsControllerDelegate, CollectionMapViewControllerDelegate>{
CollectionMapViewController* mapVC;
}
#property (nonatomic, retain) CollectionMapViewController* mapVC;
The problem is that it adds the MKMapView to the top of the screen:
I tried to constrain the MKMapView to the bottom of the screen by adding following code to viewDidLoad of MapViewController
mapView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *bottom =[NSLayoutConstraint
constraintWithItem:mapView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:0.f];
//Add constraints to the Parent
[self.view addConstraint:bottom];
But it just makes the map go black (or more likely moves it completely off the screen?).
What I am trying to get is this:
I would appreciate any help! Thank you so much!
When you add mapView.translatesAutoresizingMaskIntoConstraints = NO; your map rect size is equal to zero if there are not enough constraints to define the correct frame, that is why you have your screen black, you need define all the constraints needed by your MKMapView
Updated using dynamic height constraints
try with this code
self.mapView.translatesAutoresizingMaskIntoConstraints = NO;
CGFloat mapHeigthValue = self.view.frame.size.height/3; //setting the mapView heigth = 1/3 of view height this is an example
NSArray * verticalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:[mapView(%f)]|",mapHeigthValue] options:0 metrics:nil views:#{#"mapView":self.mapView}];
NSArray * horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[mapView]|" options:0 metrics:nil views:#{#"mapView":self.mapView}];
//Add constraints to the Parent
[self.view addConstraints:verticalConstraints];
[self.view addConstraints:horizontalConstraints];
In viewDidLoad:
mapView.translatesAutoresizingMaskIntoConstraints = NO;
/*Set width and height of mapview */
NSLayoutConstraint *widthConst = [NSLayoutConstraint constraintWithItem:mapView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:400];
NSLayoutConstraint *heightConst = [NSLayoutConstraint constraintWithItem:mapView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:300];
[self.view addConstraint:widthConst];
[self.view addConstraint:heightConst];
/*creater X and Y constraints for mapview */
NSLayoutConstraint *centreHorizontallyConstraint = [NSLayoutConstraint
constraintWithItem:mapView
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeCenterX
multiplier:1.0
constant:0];
[self.view addConstraint:centreHorizontallyConstraint];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint
constraintWithItem:mapView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:140];
[self.view addConstraint:bottomConstraint];

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.

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