Reputation:
I am just switching over to auto layout and before I was using:
[Btn setFrame:CGRectMake(165,164,135,35)];
But I know that for auto layout you don't use set frame. I know it's supposed to be something like:
self.constraintToAnimate = [NSLayoutConstraint constraintWithItem:label
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeBottom
multiplier:0.25
constant:0.0];
and this:
[self.scrollView addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:@"V:|-[Btn(==300)]-|"
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(Btn)]];
but I am not sure what each of these do or how the constraintsWithVisualFormat string means/ how it works.
If you could show me how to set the position, height and width of the Btn I would really appreciate it.
Thanks in advance.
Upvotes: 0
Views: 579
Reputation: 1357
Ok, I have to extrapolate a bit about the layout you are trying to achieve since you didn't exactly specify it. I am assuming you have a UIScrollView with a button as a subview that complicates things.
Since you are new to constraints, let's start with a simpler case, which is a UIButton which is a subview of a UIView. A UIButton already knows what its width and height should be based on its content, so you only need to specify its x and y location (2 constraints). I personally prefer the equation form of writing constraints rather than the visual format, so I'll use that. What you want is:
button.x = button.superview.x*1 + 0;
button.y = button.superview.x*1 + 0;
.x is a leading
constraint (leading is from the left) and .y is a top
constraint (from the top).
Next, since the constraint is between a child and it's superview, you add the constraints to the superview
[button.superview addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:button.superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:164.0]];
[button.superview addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:button.superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:165.0]];
This would position your button at (164,165) and the width and height of your button would come from the intrinsic size of the button (based on it's image / text).
So this is the simple case. Now let's turn to the scenario where your button.superview is a UIScrollView. This is more complicated because you need to think of constraints with a UIScrollview with a different mindset, namely like it is a fixed window size (the frame) into a landscape of infinite size (contentSize).
So let's say you had a UIView --> UIScrollView --> UIButton, where the UIView has a child scrollview, which in turn has a UIButton as a subview. Take this one step at a time.
1.) UIView --> UIScrollView
Constraints you write on this pair are between the frame of the UIView and the frame of the UIScrollView. This is very easy since the frame is a fixed size. So let's say you wanted the UIScrollView to be the full size of the UIView it was embedded in. You would write 4 constraints to specify it's X,Y,width and height. There are many ways to do this of course, I will list one.
scrollview.x (scrollview.frame.x) = scrollview.superview.x*1 + 0;
scrollview.y (scrollview.frame.y) = scrollview.superview.y*1 + 0;
scrollview.width (scrollview.frame.width) = scrollview.superview.width*1 + 0;
scrollview.height (scrollview.frame.height) = scrollview.superview.height*1 + 0;
In constraints, that would be:
// Let's constrain the scrollview to stick to the top and left of it's superview
[scrollView.superview addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView.superview attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
[scrollView.superview addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:scrollView.superview attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0]];
// Let's constrain the scrollview to make its width and height equal to its superview
[scrollView.superview addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:scrollView.superview attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];
[scrollView.superview addConstraint:[NSLayoutConstraint constraintWithItem:scrollView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:scrollView.superview attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]];
Ok, now the scrollview knows how to position its frame. That was the easy part.
2.) Situate the button inside the scrollview.
Ok, now you have to change your thinking. Since the scrollView is the parent of the button, you cannot constrain to the frame of the scrollView, but rather have to constrain to the contentView of the scrollView. This is theoretically an infinite plane.
So how can you constrain a view in an infinite plane? There is no setting in UIScrollView to do such a thing, so are we stuck?
No, what we need to do is define a content view for our UIScrollView. Let's drag ANOTHER view into the UIScrollView, and place the button in that view. Our view hierarchy should look like this now.
UIView (topView) --> UIScrollView --> UIView (contentView) --> UIButton (all nested).
Now we need to set up constraints to define the size of the contentView. Let's say that the contentView is the same size as the topView. Let's add constraints to make it so. The following 4 constraints are saying that the content view is the plane of the scrollview.
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTop multiplier:1.0 constant:0]];
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0]];
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0]];
[scrollView addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:scrollView attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0]];
But this is not enough because we said the scrollview was basically a window into an infinite plane. So we need 2 more constraints on our contentView to specify it's width and height. Let's just make them the same as the top level view. Notice that we are setting the constraints up between the contentView and the topView, bypassing the ScrollView altogether.
// You could make the constant parameter non-zero if you wanted it to be bigger/smaller (+/-) than the view
[topView addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:topView attribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];
[topView addConstraint:[NSLayoutConstraint constraintWithItem:contentView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:topView attribute:NSLayoutAttributeHeight multiplier:1.0 constant:0]];
Now we can finally define constraints on the button, which can be written as below so you follow along, or can be written as defined at the very top, since contentView == button.superview.
[contentView addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeTop multiplier:1.0 constant:164.0]];
[contentView addConstraint:[NSLayoutConstraint constraintWithItem:button attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:contentView attribute:NSLayoutAttributeLeading multiplier:1.0 constant:165.0]];
Now we should have properly set up all the constraints. To force a layout, just call [topView layoutIfNeeded]
Hopefully this was clear, and let me know if you are having any problems. I might have missed something as I had to write this off the top of my head :)
Upvotes: 1