Adding View Programatically With Auto Layout Gives 'NSGenericException', reason: 'Unable to install constraint on view
A couple of observations:
Your constraint references a
toItem
ofself.view.superview
. I assume you meantself.view
.You're adding the constraint to
_preView
, but you should add it toself.view
(if you make the above change; if not, you'd useself.view.superview
). You always add the constraint to the nearest shared parent.For the views you're creating programmatically, make sure to set
translatesAutoresizingMaskIntoConstraints
toNO
.Thus:
_preView.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:_preView]; NSLayoutConstraint *myConstraint = [NSLayoutConstraint constraintWithItem:_preView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-239]; [self.view addConstraint:myConstraint];
Chatting to you offline, two final observations:
Your constraints were ambiguous. In the future, you can identify that by running the app in your debugger, hitting the pause button while the app is running () and then at the
(lldb)
prompt, you can enterpo [[UIWindow keyWindow] _autolayoutTrace]
If you see
AMBIGUOUS LAYOUT
, then your constraints are not fully qualified (and thus you'll get unpredictable behavior). If you add the missing constraints, you should be able to eliminate this warning.If you want to animate constraint based views, you animate the changing of
constant
properties of theconstraints
, not by changingframe
properties yourself. For example:// create subview UIView *subview = [[UIView alloc] init]; subview.backgroundColor = [UIColor lightGrayColor]; subview.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:subview]; // create dictionary for VFL commands NSDictionary *views = @{@"subview" : subview, @"superview" : self.view}; // add horizontal constraints [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[subview]|" options:0 metrics:nil views:views]]; // set the height of the offscreen subview to be the same as its superview [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[subview(==superview)]" options:0 metrics:nil views:views]]; // set the location of the subview to be just off screen below the current view NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:self.view.bounds.size.height]; [self.view addConstraint:constraint]; // then in two seconds, animate this subview back on-screen (i.e. change the top constraint `constant` to zero) double delayInSeconds = 2.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ constraint.constant = 0.0; [UIView animateWithDuration:1.0 animations:^{ [self.view layoutIfNeeded]; }]; });
Comments
-
Gaurav Wadhwani almost 2 years
I am adding a view as a subview using
[self.view addSubview:myView]
. This works fine in portrait mode. However, it doesn't work at all in landscape. How do I add layout constraints programatically?My view currently looks like portrait rectangle and I need it to look like landscape rectangle in landscape mode.
I tried this code to see how constraints in code work but it always results in an exception. The code is:
[self.view addSubview:_preView]; NSLayoutConstraint *myConstraint = [NSLayoutConstraint constraintWithItem:_preView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view.superview attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-239]; [_preView addConstraint:myConstraint];
This always results in an exception. I know the above code just attempts to ensure that the bottom of preview is 239px above the bottom of main view. But that doesn't work either.
Could you help me out with sorting this so that I can resolve the landscape issue?
UPDATE
The exception generated is:
2013-08-05 16:13:28.889 Sample Code[33553:c07] *** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint reference something from outside the subtree of the view? That's illegal. constraint:<NSLayoutConstraint:0x912c430 UIView:0x8561340.bottom == UILayoutContainerView:0x8257340.bottom - 20> view:<UIView: 0x85774e0; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; autoresizesSubviews = NO; layer = <CALayer: 0x8577490>>' *** First throw call stack: (0x1a04012 0x173be7e 0x1a03deb 0x12ee4a0 0xbb983e 0xbb9a27 0xbb9b76 0xbb9d3b 0xbb9c4d 0x1c0d9 0x11395b3 0x19c3376 0x19c2e06 0x19aaa82 0x19a9f44 0x19a9e1b 0x24027e3 0x2402668 0x67fffc 0x2d3d 0x2c65) libc++abi.dylib: terminate called throwing an exception (lldb)
I have added the subview before adding in the constraint so I am pretty sure the view is in hierarchy.
UPDATE 2
I set the parent view's property to `Autoresize Subviews' in IB. The subview now converts into landscape rectangle when the device is turned but its too narrow. I now need the code to make sure its of correct width maybe?