Adding a view using the automatic layout "NSGenericException", reason: "Unable to set view restriction

I add the view as a subview using [self.view addSubview:myView] . This works great in portrait mode. However, it does not work at all in the landscape. How to add software layout constraints?

Currently, my look looks like a portrait rectangle, and I need it to look like a landscape rectangle in landscape mode.

I tried this code to see how the limitations of the code work, but always throw an exception. Code:

 [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 that the code above is simply trying to ensure that the bottom of the preview is 239 pixels higher than the bottom of the main view. But that doesn't work either.

Could you help me figure this out to solve the landscape problem?

UPDATE

Exception thrown:

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 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 added a subview before adding to the constraint, so I'm sure the view is in a hierarchy.

UPDATE 2

I set the parent view property `Autoresize Subviews' to IB. Subview now converts to landscape rectangle when the device is rotated, but it is too narrow. Do I need code now to make sure it has the correct width?

+6
source share
3 answers

A few observations:

  • Your restriction refers to toItem of self.view.superview . I assume you meant self.view .

  • You add a constraint to _preView , but you have to add it to self.view (if you make the above change, and if not, use self.view.superview ). You always add a constraint to the closest common parent.

  • For views that you create programmatically, be sure to set translatesAutoresizingMaskIntoConstraints to NO .

    In this way:

     _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 with you offline, the last two comments:

  • Your limitations were mixed. In the future, you can determine that by launching the application in your debugger by clicking the pause button while the application is running ( enter image description here ), and then at the prompt (lldb) you can enter

    po [[UIWindow keyWindow] _autolayoutTrace]

    ambiguous layout

    If you see AMBIGUOUS LAYOUT , then your restrictions will not be fully qualified (and therefore you will get unpredictable behavior). If you add the missing restrictions, you must eliminate this warning.

  • If you want to animate views based on constraints, you are activating the constant properties of constraints , rather than by changing the frame properties yourself. For instance:

      // 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 (ie 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]; }]; }); 
+37
source

From your code above, there are 2 problems. 1. A constraint should be added to the parentview (self.view or self.view.superview, if necessary). 2. Elements that are part of myConstraint must be present in the view hierarchy to which you add your constraints.

My suggestion was to check if your myConstraint can be formed using _preView and self.view, add _preView to self.view as a subview, and then add myConstraint to self.view.

In addition, restrictions should ideally be placed in the -(void)updateConstraints in your view (if you have a custom view), and you should call [self setNeedsUpdateConstraints]; in your view whenever you want updateConstraints to be called in your view (after initializing your view, after rotation, etc.). You will not call updateConstraints directly.

0
source

There are several things in Auto Layouts. When you add layout constraints, make sure they are not ambiguous. Ambiguous layout will result in undefined behavior on your display. Therefore, it’s a good idea to use IB, which will never allow you to create an ambiguous layout, but you need to go through all the restrictions to make sure they are valid.

If you want to do this programmatically, I suggest you use Visual language .

Before using the layout, it will be useful to read the tips .

0
source

Source: https://habr.com/ru/post/951040/


All Articles