UIStackView "Unable to satisfy constraints at the same time" on squeaky hidden views

When my UIStackView lines are compressed, they trigger AutoLayout warnings. However, they are displayed perfectly, and nothing else is wrong, except for these types of registration:

It is not possible to satisfy restrictions at the same time. Probably at least one of the restrictions in the following list is one that you do not want. Try this: (1) look at each constraint and try to figure out what you are not expecting; (2) find the code that added unwanted restrictions or restrictions and fix it. (Note: If you see NSAutoresizingMaskLayoutConstraints that you do not understand, refer to the documentation for the UIView property, translates AutoresizingMaskIntoConstraints) (

So, I'm not sure how to fix this, but it does not seem to break anything other than the fact that you are annoying.

Does anyone know how to solve it? Interestingly, layout constraints are often noted with 'UISV-hiding' , indicating that perhaps he should ignore the minimum heights for subviews or something in this case?

+72
ios uikit autolayout ios9 uistackview
Sep 06 '15 at 20:54
source share
13 answers

You get this problem because when you install a hidden subvect from UIStackView it first limits its height to zero to animate it.

The following error appeared:

 2015-10-01 11:45:13.732 <redacted>[64455:6368084] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5be508d0 V:|-(8)-[UISegmentedControl:0x7f7f5bec4180] (Names: '|':UIView:0x7f7f5be69d30 )>", "<NSLayoutConstraint:0x7f7f5bdfbda0 'UISV-hiding' V:[UIView:0x7f7f5be69d30(0)]>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7f7f5be18c80 V:[UISegmentedControl:0x7f7f5bec4180]-(8)-| (Names: '|':UIView:0x7f7f5be69d30 )> Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful. 

What I was trying to do was place a UIView inside my UIStackView containing an UISegmentedControl insert of 8pts on each edge.

When I set it to hidden, it will try to limit the container view to zero height, but since I have a set of restrictions from top to bottom, a conflict has arisen.

To fix the problem, I changed my 8pt upper priority to lower restrictions from 1000 to 999, so the UISV-hiding restriction can take precedence if necessary.

+168
01 Oct '15 at 11:02
source share

I had a similar problem, which was not easy to solve. In my case, I had a stack view built into the stack view. The internal UIStackView had two labels and a specified non-zero interval.

When you call addArrangedSubview (), it automatically creates restrictions similar to the following:

 V:|[innerStackView]| | = outerStackView V:|[label1]-(2)-[label2]| | = innerStackView 

Now, when you try to hide innerStackView, you get a warning about ambiguous constraints.

To understand why, first look at why this does not happen when innerStackView.spacing is 0 . When you call innerStackView.hidden = true , @liamnichols was right ... outerStackView magically intercept this call and create a 0 height constraint UISV hiding with a priority of 1000 (required). Presumably, this means that the elements in the stack view will be animated out of sight if your hidden code is called in the UIView.animationWithDuration() block. Unfortunately, there is no way to prevent this restriction from being added. However, you will not receive the warning “Unable to satisfy constraints at the same time” (USSC) because the following occurs:

  • label1 height set to 0
  • the interval between the two marks has already been defined as 0
  • label2 height set to 0
  • InnerStackView height is set to 0

It is clear that these 4 restrictions can be fulfilled. Browsing the stack simply wraps everything in a pixel 0 inches high.

Now, returning to the example with an error, if we set spacing to 2 , we have the following restrictions:

  • label1 height set to 0
  • the distance between the two marks was automatically created by representing the stack as 2 pixels with a priority of 1000.
  • label2 height set to 0
  • InnerStackView height is set to 0

The stack view cannot have a maximum of 0 pixels, and its contents must be 2 pixels. Restrictions cannot be met.

Note. This behavior can be seen with a simpler example. Just add the UIView to the stack view as an organized view. Then set a height limit for this UIView with a priority of 1000. Now try to call it hidden.

Note. For some reason this only happened when the view on the stack was subordinate to UICollectionViewCell or UITableViewCell. However, you can still reproduce this behavior outside the cell by calling innerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) in the next run loop after hiding the view of the inner stack.

Note. Even if you try to execute the code in UIView.performWithoutAnimations, the stack view will still add a height limit of 0, which will trigger a USSC warning.




There are at least 3 solutions to this problem:

  • Before hiding any element in the stack view, check if it is a stack view, and if so, change spacing to 0 .. This is annoying because you need to reverse the process (and remember the original interval) when you show the content again.
  • Instead of hiding items in the stack view, call removeFromSuperview . This is even more annoying because when you change the process, you need to remember where to insert the deleted item. You can optimize only by calling removeArrangedSubview and then hiding, but there is a lot of bookkeeping that still needs to be done.
  • Wrap nested stack views (that have nonzero spacing ) in a UIView. Set at least one restriction as an optional priority (999 or lower). This is the best solution, since you do not need to do any accounting operations. In my example, I created upper, leading, and final constraints of 1000 between the stack view and the shell view, and then created a 999 constraint from the bottom of the stack view to the wrapper view. Thus, when the representation of the external stack creates a zero-height constraint, the 999 constraint is violated and you do not see the USSC warning. (Note: this seems like a solution if the contentView.translatesAutoResizingMaskToConstraints subclass of UICollectionViewCell is set to false )



In short, the reasons you get this behavior are:

  • Apple automatically creates 1000 priority restrictions for you when you add managed objects to the stack view.
  • Apple automatically creates a 0-height constraint for you when you hide the view in the stack view.

If Apple (1) allowed you to specify the priority of restrictions (especially spacers) or (2) allowed you to refuse the automatic restriction of UISV-hiding , this problem will be easily resolved.

+38
Jun 27 '16 at 23:17
source share

In most cases, this error can be resolved by lowering the priority of constraints to resolve conflicts.

+3
Sep 06 '15 at 21:42
source share

When you set up a hidden view, UIStackview will try to animate it. If you need this effect, you will need to set the correct priority for the constraints so that they do not conflict (as many of them suggested above).

However, if you don’t need the animation (perhaps you hide it in ViewDidLoad), you can simply removeFromSuperview , which will have the same effect, but without any problems with restrictions, as they will be removed along with the view.

+2
Sep 05 '16 at 18:32
source share

Based on the @Senseful answer, here is the UIStackView extension to wrap the stack view in the view and apply the restrictions that it recommends:

 /// wraps in a `UIView` to prevent autolayout warnings when a stack view with spacing is placed inside another stack view whose height might be zero (usually due to `hidden` being `true`). /// See http://stackoverflow.com/questions/32428210 func wrapped() -> UIView { let wrapper = UIView() translatesAutoresizingMaskIntoConstraints = false wrapper.addSubview(self) for attribute in [NSLayoutAttribute.Top, .Left, .Right, .Bottom] { let constraint = NSLayoutConstraint(item: self, attribute: attribute, relatedBy: .Equal, toItem: wrapper, attribute: attribute, multiplier: 1, constant: 0) if attribute == .Bottom { constraint.priority = 999 } wrapper.addConstraint(constraint) } return wrapper } 

Instead of adding stackView use stackView.wrapped() .

+1
Aug 04 '16 at 18:23
source share

First, as others suggested, make sure that there are restrictions that you can control, i.e. non-restrictions inherent in UIStackView are set to priority 999 so that they can be overridden when hiding the view.

If you are still experiencing a problem, the problem is most likely related to the interval in the hidden stackview. My solution was to add a UIView as a separator and set the UIStackView span to zero. Then set the View.height or View.width limits (depending on the vertical or horizontal stack) to the StackView distance.

Then change the priorities of content compression and content compression of your newly added views. You may need to change the distribution of the parent StackView.

All of the above can be done in Interface Builder. You can also hide / show some of the newly added views programmatically so that you do not have an unwanted interval.

+1
Sep 11 '16 at 0:26
source share

I recently struggled with auto layout errors by hiding UIStackView . Instead of doing a bunch of book storage and wrapping in UIViews , I decided to create an output for my parentStackView and outputs for the children I want to hide / show.

 @IBOutlet weak var parentStackView: UIStackView! @IBOutlet var stackViewNumber1: UIStackView! @IBOutlet var stackViewNumber2: UIStackView! 

In the storyboard, what my parent table looks like:

enter image description here

It has 4 children, and each of the children has a bunch of stack views inside them. When you hide the view of the stack, if it receives user interface elements, which are also representations of the stack, you will see a stream of errors in the automatic layout. Instead of hiding, I decided to remove them.

In my example, parentStackViews contains an array of 4 elements: Top Stack View, StackViewNumber1, Stack View Number 2, and Stop Button. Their indices in arrangedSubviews are 0, 1, 2, and 3, respectively. When I want to hide it, I just delete it from the parentStackView's arrangedSubviews array. Since it is not weak, it lingers in memory, and you can simply return it back to your desired index later. I do not reinitialize it, so it just hangs until it is needed, but it does not inflate memory.

So basically, you can ...

1) Drag and drop IBOutlets for your parent stack and the children you want to hide / show in the storyboard.

2) If you want to hide them, delete the stack that you want to hide from the parentStackView's arrangedSubviews array.

3) Call self.view.layoutIfNeeded() using UIView.animateWithDuration .

Note that the last two elements of stackViews are not weak . You need to keep them around when you show them.

Let's say I want to hide stackViewNumber2:

 parentStackView.removeArrangedSubview(stackViewNumber2) stackViewNumber2.removeFromSuperview() 

Then we animate it:

 UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil) 

If you want to “show” stackViewNumber2 later, you can simply insert it into the desired parentStackView arrangedSubviews index and spice up the update.

 parentStackView.removeArrangedSubview(stackViewNumber1) stackViewNumber1.removeFromSuperview() parentStackView.insertArrangedSubview(stackViewNumber2, at: 1) // Then animate it UIView.animate(withDuration: 0.25, delay: 0, usingSpringWithDamping: 2.0, initialSpringVelocity: 10.0, options: [.curveEaseOut], animations: { self.view.layoutIfNeeded() }, completion: nil) 

I found this to be a lot easier than doing constraint bookkeeping, tinkering with priorities, etc.

If you have something that you want to hide by default, you can simply put it on the storyboard and delete it in viewDidLoad and update it without animation using view.layoutIfNeeded() .

+1
Mar 17 '17 at 15:31
source share

Perhaps you created a restriction when working with a specific size class (ex: wCompact hRegular), and then you created a duplicate when switching to another size class (for example: wAny hAny). check the restrictions of UI objects in different size classes and see if there are anomalies with restrictions. you should see red lines indicating clashing constraints. I can’t put a picture until I get 10 reputation points, sorry: /

0
Sep 06 '15 at
source share

I wanted to hide the whole UIStackView at a time, but I was getting the same errors as the OP, this fixed it for me:

 for(UIView *currentView in self.arrangedSubviews){ for(NSLayoutConstraint *currentConstraint in currentView.constraints){ [currentConstraint setPriority:999]; } } 
0
Mar 14 '16 at 15:15
source share

I had a number of buttons with height restrictions. This happens when one button is hidden. Setting the priority of the button height limit to 999 solved the problem.

0
07 Oct '16 at 12:25
source share

I encountered the same errors with the built-in Stack Views, although everything worked fine while working.

I solved the constraint errors by hiding all the sub- isHidden = true first (setting isHidden = true ) before hiding the view of the parent stack.

It did not have all the difficulty of removing subviews, maintaining an index if necessary to add them.

Hope this helps.

0
Apr 23 '17 at 19:09 on
source share

This error has nothing to do with UIStackView. This happens when you have conflicting restrictions with the same priorities. For example, if you have a restriction, it is indicated that the width of your view is 100, and you have another limitation at the same time that the width of the view is 25% of its container. Obviously, there are two conflicting limitations. The solution is to remove from them.

-2
Sep 14 '15 at
source share

NOP with [mySubView removeFromSuperview]. Hope this can help someone :)

-2
Aug 09 '16 at 4:45
source share



All Articles