Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating layout constraints programmatically

I know that a lot people already asked tons of questions about this, but even with the answers I can't make it work.

When I'm dealing with constraints on storyboard, it's easy but in code I have a hard time. I try, for example, to have a view that stays on the right side and has the height of the screen according the screen orientation. This is my code:

UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 748)]; myView.backgroundColor = [UIColor redColor]; [self.view addSubview:myView]; [self.view addConstraints:[NSLayoutConstraint     constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"     options:0 metrics:nil     views:NSDictionaryOfVariableBindings(myView)]]; 

It doesn't satisfy some constraints. I don't see what is wrong. Also, why can't I use a property like self.myView instead of a local variable like myView?

like image 463
pierre23 Avatar asked Oct 10 '12 19:10

pierre23


2 Answers

When using Auto Layout in code, setting the frame does nothing. So the fact that you specified a width of 200 on the view above, doesn't mean anything when you set constraints on it. In order for a view's constraint set to be unambiguous, it needs four things: an x-position, a y-position, a width, and a height for any given state.

Currently in the code above, you only have two (height, relative to the superview, and y-position, relative to the superview). In addition to this, you have two required constraints that could conflict depending on how the view's superview's constraints are setup. If the superview were to have a required constraint that specifies it's height be some value less than 748, you will get an "unsatisfiable constraints" exception.

The fact that you've set the width of the view before setting constraints means nothing. It will not even take the old frame into account and will calculate a new frame based on all of the constraints that it has specified for those views. When dealing with autolayout in code, I typically just create a new view using initWithFrame:CGRectZero or simply init.

To create the constraint set required for the layout you verbally described in your question, you would need to add some horizontal constraints to bound the width and x-position in order to give a fully-specified layout:

[self.view addConstraints:[NSLayoutConstraint     constraintsWithVisualFormat:@"V:|-[myView(>=748)]-|"     options:NSLayoutFormatDirectionLeadingToTrailing     metrics:nil     views:NSDictionaryOfVariableBindings(myView)]];  [self.view addConstraints:[NSLayoutConstraint     constraintsWithVisualFormat:@"H:[myView(==200)]-|"     options:NSLayoutFormatDirectionLeadingToTrailing     metrics:nil     views:NSDictionaryOfVariableBindings(myView)]]; 

Verbally describing this layout reads as follows starting with the vertical constraint:

myView will fill its superview's height with a top and bottom padding equal to the standard space. myView's superview has a minimum height of 748pts. myView's width is 200pts and has a right padding equal to the standard space against its superview.

If you would simply like the view to fill the entire superview's height without constraining the superview's height, then you would just omit the (>=748) parameter in the visual format text. If you think that the (>=748) parameter is required to give it a height - you don't in this instance: pinning the view to the superview's edges using the bar (|) or bar with space (|-, -|) syntax, you are giving your view a y-position (pinning the view on a single-edge), and a y-position with height (pinning the view on both edges), thus satisfying your constraint set for the view.

In regards to your second question:

Using NSDictionaryOfVariableBindings(self.myView) (if you had an property setup for myView) and feeding that into your VFL to use self.myView in your VFL text, you will probably get an exception when autolayout tries to parse your VFL text. It has to do with the dot notation in dictionary keys and the system trying to use valueForKeyPath:. See here for a similar question and answer.

like image 104
larsacus Avatar answered Oct 23 '22 17:10

larsacus


Hi I have been using this page a lot for constraints and "how to". It took me forever to get to the point of realizing I needed:

myView.translatesAutoresizingMaskIntoConstraints = NO; 

to get this example to work. Thank you Userxxx, Rob M. and especially larsacus for the explanation and code here, it has been invaluable.

Here is the code in full to get the examples above to run:

UIView *myView = [[UIView alloc] init]; myView.backgroundColor = [UIColor redColor]; myView.translatesAutoresizingMaskIntoConstraints = NO;  //This part hung me up  [self.view addSubview:myView]; //needed to make smaller for iPhone 4 dev here, so >=200 instead of 748 [self.view addConstraints:[NSLayoutConstraint                            constraintsWithVisualFormat:@"V:|-[myView(>=200)]-|"                            options:NSLayoutFormatDirectionLeadingToTrailing                            metrics:nil                            views:NSDictionaryOfVariableBindings(myView)]];  [self.view addConstraints:[NSLayoutConstraint                            constraintsWithVisualFormat:@"H:[myView(==200)]-|"                            options:NSLayoutFormatDirectionLeadingToTrailing                            metrics:nil                            views:NSDictionaryOfVariableBindings(myView)]]; 
like image 39
BriOnH Avatar answered Oct 23 '22 16:10

BriOnH