Make constraints for subviews programmatically - ios

I need to create a UISlider and put it above an existing slider.
I do know how to create constraints for a view if I want to attach it to its superview:
UIView *superview = view.superview;
[view setValue: [NSNumber numberWithBool: FALSE] forKey: #"translatesAutoresizingMaskIntoConstraints"];
NSLayoutConstraint *topConstraint =[NSLayoutConstraint
constraintWithItem: view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem: superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
NSLayoutConstraint *bottomConstraint =[NSLayoutConstraint
constraintWithItem: view
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem: superview
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
NSLayoutConstraint *leadingConstraint =[NSLayoutConstraint
constraintWithItem: view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem: superview
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0];
NSLayoutConstraint *trailingConstraint =[NSLayoutConstraint
constraintWithItem: view
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem: superview
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0];
NSArray *constraints = #[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint];
[superview addConstraints: constraints];
But the same method does not work when I need to attach two subviews together. Say, I have view1 as subview of superview. It has been created some time ago. Now I need another one (view2) to have the same positioning inside superview.
Something like
UIView *superview = view1.superview;
UIView *view2 = [[UIView alloc] init];
[superview addSubview: view2];
[view2 setValue: [NSNumber numberWithBool: FALSE] forKey: #"translatesAutoresizingMaskIntoConstraints"];
NSLayoutConstraint *topConstraint =[NSLayoutConstraint
constraintWithItem: view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem: view2
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];
NSLayoutConstraint *bottomConstraint =[NSLayoutConstraint
constraintWithItem: view1
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem: view2
attribute:NSLayoutAttributeBottom
multiplier:1.0
constant:0.0];
NSLayoutConstraint *leadingConstraint =[NSLayoutConstraint
constraintWithItem: view1
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem: view2
attribute:NSLayoutAttributeLeading
multiplier:1.0
constant:0.0];
NSLayoutConstraint *trailingConstraint =[NSLayoutConstraint
constraintWithItem: view1
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem: view2
attribute:NSLayoutAttributeTrailing
multiplier:1.0
constant:0.0];
NSArray *constraints = #[topConstraint, bottomConstraint, leadingConstraint, trailingConstraint];
[superview addConstraints: constraints];
breaks everything.

Looks like you just have it backward...
You want to constrain view2 to view1:
[NSLayoutConstraint
constraintWithItem: view2 // <-- constrain this view
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem: view1 // <-- to this view
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0];

Related

Adding UIButton To UITableView Programmatically Wrong Spot

I'm trying to get a UIButton added to a TableView, where it sits in the bottom right corner of the table view, 20 from the right edge, and 20 from the bottom. However, it ends up sticking the button at the top left edge. What am I doing wrong?
UIButton *goToTop = [UIButton buttonWithType:UIButtonTypeCustom];
[goToTop setImage:redGo forState:UIControlStateNormal];
[goToTop addTarget:self action:#selector(beginCampaign) forControlEvents:UIControlEventTouchUpInside];
[goToTop setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[goToTop.layer setBorderColor:[[UIColor redColor] CGColor]];
[self.tableView addSubview:goToTop];
goToTop.translatesAutoresizingMaskIntoConstraints = NO;
/* Leading space to superview */
NSLayoutConstraint *leftButtonXConstraint = [NSLayoutConstraint
constraintWithItem:goToTop attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual toItem:self.tableView attribute:
NSLayoutAttributeLeft multiplier:1.0 constant:20];
/* Top space to superview Y*/
NSLayoutConstraint *leftButtonYConstraint = [NSLayoutConstraint
constraintWithItem:goToTop attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual toItem:self.tableView attribute:
NSLayoutAttributeTop multiplier:1.0f constant:20];
/* Fixed width */
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:goToTop
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:60];
/* Fixed Height */
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:goToTop
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:60];
/* 4. Add the constraints to button's superview*/
[self.tableView addConstraints:#[leftButtonXConstraint, leftButtonYConstraint, widthConstraint, heightConstraint]];
Here is how I would like it:
Here is how it appears:
You have set your constraints to the top left of the table view not the bottom right.
Change this:
/* Leading space to superview */
NSLayoutConstraint *leftButtonXConstraint = [NSLayoutConstraint
constraintWithItem:goToTop attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual toItem:self.tableView attribute:
NSLayoutAttributeLeft multiplier:1.0 constant:20];
/* Top space to superview Y*/
NSLayoutConstraint *leftButtonYConstraint = [NSLayoutConstraint
constraintWithItem:goToTop attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual toItem:self.tableView attribute:
NSLayoutAttributeTop multiplier:1.0f constant:20];
To this:
/* Leading space to superview */
NSLayoutConstraint *leftButtonXConstraint = [NSLayoutConstraint
constraintWithItem:goToTop attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual toItem:self.tableView attribute:
NSLayoutAttributeRight multiplier:1.0 constant:20];
/* Top space to superview Y*/
NSLayoutConstraint *leftButtonYConstraint = [NSLayoutConstraint
constraintWithItem:goToTop attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual toItem:self.tableView attribute:
NSLayoutAttributeBottom multiplier:1.0f constant:20];

How to add container view on scrollview using constraint with item formate

I am new for auto-layouts and i am trying to add one container view on ScrollView using auto-layouts "constraint with item" formate but I can't adding using my code.
I know how to add using visual formate but I want to do this process using constraint with item formate. Please help me!
My code:
#import "ViewController3.h"
#interface ViewController3 ()
{
UIScrollView * scrollView;
UIView * containerView;
}
#end
#implementation ViewController3
- (void)viewDidLoad {
[super viewDidLoad];
scrollView = [[UIScrollView alloc] init];
scrollView.backgroundColor = [UIColor lightGrayColor];
scrollView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:scrollView];
containerView = [[UIView alloc] init];
containerView.backgroundColor = [UIColor orangeColor];
containerView.translatesAutoresizingMaskIntoConstraints = NO;
[scrollView addSubview:containerView];
//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 containerview
NSLayoutConstraint * constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem: scrollView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
[scrollView addConstraint:constraint2];
}
With Autolayout, you don't need to set scrollview's contentSize explicitly, but you have to provide enough clues to let Autolayout system infer what exactly your scrollview's contentSize is.
There are generally two ways to layout UIScrollView with Autolayout, mixed or pure Autolayout.Check this:https://developer.apple.com/library/ios/technotes/tn2154/_index.html.
If it is pure Autolayout, you can achieve that by your containerView's subviews, that is, your subviews do not rely on the scroll view to get their size. Or you can just tie your containerView's width and height to any view outside your scrollview, like self.view, or to a fixed value.
E.g,
You can add four more lines :
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
[self.view addConstraint:constraint2];
constraint2 = [NSLayoutConstraint constraintWithItem:containerView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeHeight multiplier:1 constant:0];
[self.view addConstraint:constraint2];

How can we provide horizontal spacing between buttons using auto-layouts(constraint with visual formate)

Hi i am trying to insert three button programmatically on my view-controller using auto-layouts and here i would like keep horizontal spacing between buttons "10" but it is not setting properly please help me using constraint with "visual formate"
my code:-
NSDictionary * views = NSDictionaryOfVariableBindings(accessoryView,leftButton,firstButton,rightButton);
//middle button
constraint = [NSLayoutConstraint constraintWithItem:firstButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:40.f];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:firstButton attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:firstButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem: nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:50.0f];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:firstButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem: nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:30.0f];
[self.view addConstraint:constraint];
//Left button
constraint = [NSLayoutConstraint constraintWithItem:leftButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:40.f];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:leftButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem: nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:50.0f];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:leftButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem: nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:30.0f];
[self.view addConstraint:constraint];
//Right button
constraint = [NSLayoutConstraint constraintWithItem:rightButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:40.f];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:rightButton attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem: nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:50.0f];
[self.view addConstraint:constraint];
constraint = [NSLayoutConstraint constraintWithItem:rightButton attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem: nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:30.0f];
[self.view addConstraint:constraint];
//Horizental spacing
NSArray * horizontalConstraintsforbuttons = [NSLayoutConstraint constraintsWithVisualFormat:#"H:|[leftButton]-10-[firstButton]-10-[rightButton]|" options:0 metrics:nil views:views];
[self.view addConstraints:horizontalConstraintsforbuttons];
Try this.... give button1 trailing equal button2 leading with constant whatever you want
// btn1.trailing = btn2.leading
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:btn2
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:btn1
attribute: NSLayoutAttributeTrailing
multiplier:1
constant:10]];
// btn2.trailing = btn3.leading
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:btn3
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:btn2
attribute: NSLayoutAttributeTrailing
multiplier:1
constant:10]];
So it becomes -|btn1|-10-|btn2|-10-|btn3|-

NSLayoutConstraint inside UITableViewCell crashes app

I'm trying to position an image in the center of a UITableViewCell with NSLayoutConstraints. I'm using the code below for that:
NSLayoutConstraint *cn = [NSLayoutConstraint constraintWithItem:self.image
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeWidth
multiplier:1
constant:200];
[self.image addConstraint: cn];
cn = [NSLayoutConstraint constraintWithItem:self.image
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeHeight
multiplier:1
constant:200];
[self.image addConstraint:cn];
Also, I would like the image to be 80% of the UITableViewCells height and have the same width - so it's square. However, currently my app crashes and throws this error: Impossible to set up layout with view hierarchy unprepared for constraint.
What am I doing wrong?
As it turns out, I had to add the image to the cell.contentView, so that it was actually available as a subview.
This is the completed working code:
NSLayoutConstraint *cn = [NSLayoutConstraint constraintWithItem:self.image
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeHeight
multiplier:0.7
constant:0];
[cell.contentView addConstraint: cn];
cn = [NSLayoutConstraint constraintWithItem:self.image
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:cell.contentView
attribute:NSLayoutAttributeHeight
multiplier:0.7
constant:0];
[cell.contentView addConstraint:cn];
NSLayoutConstraint *constraintX = [NSLayoutConstraint constraintWithItem:self.image attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0];
NSLayoutConstraint *constraintY = [NSLayoutConstraint constraintWithItem:self.image attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:cell.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0];
[cell.contentView addConstraint:constraintX];
[cell.contentView addConstraint:constraintY];
Exactly what is "self.image" referring to? Is it a property of your View Controller (this would be definitely wrong)? Seems to me it should be "cell.image" where each of your cells should have it's own reference to an image.

Expand views on changing orientation and screen size in auto layout

I have a UIImageView which I need to expand (height and width) on changing orientation and screen size. I am using auto layout constraints for that.
topImageView.contentMode = UIViewContentModeScaleAspectFit;
topImageView.backgroundColor = [UIColor clearColor];
topImageView.layer.cornerRadius = 5.0f;
topImageView.clipsToBounds = YES;
topImageView.translatesAutoresizingMaskIntoConstraints = NO;
if(login_DO.logoPath)
[topImageView loadImage:login_DO.logoPath];
[self.view addSubview:topImageView];
NSArray *horizontalConstraints =
[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"H:|-(%i)-[topImageView(%f)]",X_OFFSET,VIEW_FRAME_WIDTH-X_OFFSET*2]
options:0 metrics:nil views:#{#"topImageView": topImageView}];
NSArray *verticalConstraints =
[NSLayoutConstraint constraintsWithVisualFormat:[NSString stringWithFormat:#"V:|-(%f)-[topImageView(80)]",navHeight]
options:0 metrics:nil views:#{#"topImageView": topImageView}];
[self.view addConstraints:horizontalConstraints];
[self.view addConstraints:verticalConstraints];
NSLayoutConstraint *leadingMarginForImageConstraint = [NSLayoutConstraint
constraintWithItem:topImageView attribute:NSLayoutAttributeLeadingMargin
relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self.view attribute:
NSLayoutAttributeLeadingMargin multiplier:1.0 constant:X_OFFSET];
NSLayoutConstraint *topMarginForImageConstraint = [NSLayoutConstraint
constraintWithItem:topImageView attribute:NSLayoutAttributeTopMargin
relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self.view attribute:
NSLayoutAttributeTopMargin multiplier:1.0 constant:VIEW_FRAME_WIDTH-X_OFFSET*2];
[self.view addConstraints:#[ leadingMarginForImageConstraint,
topMarginForImageConstraint]];
But the image is not expanding. I am new to auto layouts. Am I missing any constraint?
you can change the imageBottomConstraint from -navHeight to some other value from bottom.
avoid using VIEW_FRAME_WIDTH cause it change when you change orientation.
UIView *superview = self.view;
NSLayoutConstraint *imageTopConstraint = [NSLayoutConstraint
constraintWithItem:topImageView attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual toItem:superview
attribute:NSLayoutAttributeTop multiplier:1.0 constant:navHeight];
NSLayoutConstraint *imageBottomConstraint = [NSLayoutConstraint
constraintWithItem:topImageView attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual toItem:superview
attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-navHeight];
NSLayoutConstraint *imageLeftConstraint = [NSLayoutConstraint
constraintWithItem:topImageView attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual toItem:superview attribute:
NSLayoutAttributeLeft multiplier:1.0 constant:X_OFFSET];
NSLayoutConstraint *imageRightConstraint = [NSLayoutConstraint
constraintWithItem:topImageView attribute:NSLayoutAttributeRight
relatedBy:NSLayoutRelationEqual toItem:superview attribute:
NSLayoutAttributeRight multiplier:1.0 constant:-X_OFFSET];
[superview addConstraints:#[imageBottomConstraint ,
imageLeftConstraint, imageRightConstraint,
imageTopConstraint]];
for more help check http://www.tutorialspoint.com/ios/ios_auto_layouts.htm
or try using https://github.com/marcoarment/CompactConstraint
let me know if it helped.
I tested the following code that adds an ImageView with Globe.png and add constraints so it appears as you describe. The difference is just to pinch all side edges to the superview (self.view) and then assign the constraints to the superview:
-(void)addImageView{
topImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Globe.png"]]; // Added test image
topImageView.contentMode = UIViewContentModeScaleAspectFit;
topImageView.backgroundColor = [UIColor clearColor];
topImageView.layer.cornerRadius = 5.0f;
topImageView.clipsToBounds = YES;
topImageView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:topImageView];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:topImageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
NSLayoutConstraint *bottomConstraint = [NSLayoutConstraint constraintWithItem:topImageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:topImageView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0];
NSLayoutConstraint *rightConstraint = [NSLayoutConstraint constraintWithItem:topImageView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:0];
[self.view addConstraints:#[topConstraint, bottomConstraint, leftConstraint, rightConstraint]]; //Note constraints are added to the superView
}

Resources