UIStackView“无法同时满足约束”的“挤压”隐藏的意见

当我的UIStackView“行”被挤压,他们抛出AutoLayout警告。 但是,它们显示正常,除了这些logging之外没有别的错误:

无法同时满足约束。 下面列表中的至less一个约束可能是你不想要的。 试试这个:(1)看看每一个约束,并试图找出你不期望的; (2)find添加不需要的约束或约束的代码并修复它。 (注意:如果你看到你不明白的NSAutoresizingMaskLayoutConstraints,请参阅UIView属性的文档translatesAutoresizingMaskIntoConstraints)(

所以,我不知道如何解决这个问题,但除了只是烦人之外,似乎没有什么可以打破的。

有谁知道如何解决它? 有趣的是,布局约束常常被标记为“UISV-hiding” ,表明可能应该忽略子视图的高度最小值或在这种情况下的某些东西?

你会遇到这个问题,因为当从UIStackView子视图设置为隐藏时,它将首先将其高度限制为零,以使其animation化。

我得到以下错误:

 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. 

我想要做的是在我的UIStackView中放置一个UIView ,在每个边上包含一个由8ptsembedded的UISegmentedControl

当我将它设置为隐藏的时候,它会尝试将容器视图限制为零高度,但是因为我有一组从上到下的约束,所以发生冲突。

为了解决这个问题,我将我的8pt顶部和底部约束优先级从1000改为999,这样UISV-hiding约束可以根据需要优先考虑。

我有一个类似的问题,不容易解决。 在我的情况下,我有一个堆栈视图embedded堆栈视图。 内部UIStackView有两个标签,并指定了一个非零的间距。

当您调用addArrangedSubview()时,它将自动创build类似于以下的约束:

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

现在当你试图隐藏innerStackView时,你会得到一个模糊的约束警告。

为了理解为什么,让我们先看看为什么当innerStackView.spacing等于0不会发生这种情况。 当你调用innerStackView.hidden = true ,@liamnichols是正确的… outerStackView会奇迹般地拦截这个调用,并创build一个优先级为1000(必需)的0高度UISV隐藏约束。 大概这是为了让你的隐藏代码在UIView.animationWithDuration()块中被调用,允许堆栈视图中的元素在视图外animation。 不幸的是,似乎没有办法阻止添加这个约束。 不过,您不会得到“无法同时满足约束”(USSC)警告,因为会发生以下情况:

  1. label1的高度设置为0
  2. 两个标签之间的间隔已经被定义为0
  3. label2的高度设置为0
  4. innerStackView的高度设置为0

很明显,这4个约束条件是可以满足的。 堆栈视图只是把所有东西都弄成一个0高度的像素。

现在回到错误的例子,如果我们设置spacing2 ,我们现在有这些限制:

  1. label1的高度设置为0
  2. 两个标签之间的间隔由堆栈视图自动创build,高度为2像素,优先级为1000。
  3. label2的高度设置为0
  4. innerStackView的高度设置为0

堆栈视图不能都是0像素高,并且其内容是2像素高。 约束条件不能满足。

注意:您可以通过更简单的示例查看此行为。 只需将一个UIView作为排列的子视图添加到堆栈视图中即可。 然后在该UIView上以1000的优先级设置一个高度约束。 现在尝试调用隐藏。

注意:无论出于何种原因,这只发生在我的堆栈视图是UICollectionViewCell或UITableViewCell的子视图。 但是,在隐藏内部堆栈视图之后,仍然可以通过在下一个运行循环中调用innerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)在单元格之外重现此行为。

注意:即使您尝试在UIView.performWithoutAnimations中执行代码,堆栈视图仍将添加0高度约束,这将导致USSC警告。


这个问题至less有三种解决scheme:

  1. 在隐藏堆栈视图中的任何元素之前,请检查它是否是堆栈视图,如果是,请将spacing更改为0.这很烦人,因为无论何时再次显示内容,都需要反转过程(并记住原始间距)。
  2. 不要在堆栈视图中隐藏元素,请调用removeFromSuperview 这是更令人讨厌的,因为当你逆转过程时,你需要记住插入删除项目的位置。 你可以通过只调用removeArrangedSubview然后隐藏来进行优化,但还有很多记账工作还需要完成。
  3. 在UIView中包装嵌套的堆栈视图(其具有非零spacing )。 指定至less一个约束为不需要的优先级(999或更低)。 这是最好的解决scheme,因为你不必做任何簿记。 在我的示例中,我在栈视图和包装器视图之间创build了顶部,顶部和尾部约束条件1000,然后从堆栈视图的底部创build999约束到包装器视图。 这样当外部堆栈视图创build一个零高度约束时,999约束被打破,你看不到USSC警告。 (注意:这与解决scheme类似, 如果UICollectionViewCell子类的contentView.translatesAutoResizingMaskToConstraints设置为false

总之,你得到这种行为的原因是:

  1. 当您将pipe理的子视图添加到堆栈视图时,Apple会为您自动创build1000个优先级约束。
  2. 当您隐藏堆栈视图的子视图时,Apple自动为您创build一个0高度限制。

如果苹果或者(1)允许你指定约束的优先级(尤其是间隔 ),或者(2)允许你select退出自动UISV隐藏约束,这个问题就可以很容易地解决。

大多数情况下,这个错误可以通过降低约束优先级来解决,以消除冲突。

当您将视图设置为隐藏时, UIStackview将尝试将其移动。 如果你想得到这个效果,你需要为约束设置正确的优先级,这样它们就不会发生冲突(如上面提到的那样)。

但是,如果你不关心animation(也许你把它隐藏在ViewDidLoad中),那么你可以简单的removeFromSuperview ,这将有相同的效果,但没有任何约束的问题,因为这些将随着视图一起被删除。

基于@ Senseful的回答,下面是一个UIStackView扩展,用于在视图中包装堆栈视图,并应用他或她所推荐的约束:

 /// 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 } 

使用stackView.wrapped()代替添加你的stackView

首先,如其他人所build议的那样,确保您可以控制的约束条件(即不是UIStackView的固有约束条件)设置为优先999,以便在隐藏视图时可以覆盖它们。

如果您仍然遇到问题,那么问题可能是由于隐藏的StackViews中的间距。 我的解决scheme是添加一个UIView作为一个间隔,并将UIStackView间距设置为零。 然后将View.height或View.width约束(取决于垂直或水平堆栈)设置为StackView的间距。

然后调整新添加的视图的内容拥有和内容压缩抵抗优先级。 您可能还必须更改父级StackView的分配。

以上所有可以在Interface Builder中完成。 您可能还需要以编程方式隐藏/取消隐藏某些新添加的视图,以免造成不必要的间距。

我最近在隐藏UIStackView时遇到了自动布局错误。 我没有在parentStackView做一堆书和包装堆栈,而是select为我的parentStackView和我想要隐藏/取消隐藏的孩子创build出口。

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

在storyboard中,这是我的parentStack看起来像:

在这里输入图像说明

它有4个孩子,每个孩子都有一堆堆栈视图。 当你隐藏一个堆栈视图时,如果它也有堆栈视图的UI元素,你会看到一系列的自动布局错误。 我select删除它们,而不是隐藏。

在我的例子中, parentStackViews包含4个元素的数组:Top Stack View,StackViewNumber1,Stack View Number 2和Stop Button。 他们在arrangedSubviews的指数分别是0,1,2和3。 当我想隐藏一个,我只是从parentStackView's数组中删除它。 因为它不弱,所以它会在内存中徘徊,之后你可以把它放回到你想要的索引处。 我不是重新初始化它,所以它只是挂起,直到需要,但不会膨胀内存。

所以基本上,你可以…

1)将IBOutlets拖放到您的父堆栈以及要隐藏/取消隐藏的子区块。

2)当你想隐藏他们,从parentStackView's数组中删除你想隐藏的堆栈。

3)用UIView.animateWithDuration调用UIView.animateWithDuration self.view.layoutIfNeeded()

注意最后两个堆栈视图不weak 。 当你取消隐藏时,你需要保留它们。

比方说,我想隐藏stackViewNumber2:

 parentStackView.removeArrangedSubview(stackViewNumber2) stackViewNumber2.removeFromSuperview() 

然后animation:

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

如果您想稍后“取消隐藏” stackViewNumber2 ,则可以将其插入到所需的parentStackView arrangedSubViews索引中,并为更新添加animation。

 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) 

我发现要做比约束簿记更容易,摆弄优先等等

如果你想隐藏默认的东西,你可以把它放在故事板上,并在viewDidLoad删除它,并使用view.layoutIfNeeded()更新而不使用animation。

你可能已经创build了一个处理特定大小的类时的约束(例如:wCompact hRegular),然后当你切换到另一个大小类(例如:wAny hAny)时创build了一个重复。 检查不同大小的UI对象的约束,看看是否有约束的exception。 你应该看到红线表示碰撞约束。 我不能把一张图片,直到我得到10声望点对不起:/

我想一次隐藏整个UIStackView,但是我得到了和OP一样的错误,这个问题对我来说是固定的:

 for(UIView *currentView in self.arrangedSubviews){ for(NSLayoutConstraint *currentConstraint in currentView.constraints){ [currentConstraint setPriority:999]; } } 

我有一排高度约束的button。 隐藏一个button时会发生这种情况。 将该button高度约束的优先级设置为999已解决该问题。

我经历了与embedded堆栈视图相同的错误,尽pipe在运行时一切正常。

在隐藏父堆栈视图之前,我先通过隐藏所有子堆栈视图(设置isHidden = true )来解决约束错误。

这样做并不具有删除子排列视图的所有复杂性,在需要添加它们时维护一个索引。

希望这可以帮助。

这个错误与UIStackView无关。 当你有相同的优先权冲突限制时,会发生这种情况。 例如,如果你有一个约束说明你的视图的宽度是100,并且你有另一个约束在同一时间声明视图的宽度是它的容器的25%。 显然有两个矛盾的约束。 解决办法是删除它们。

NOP与[mySubView removeFromSuperview]。 我希望它可以帮助别人:)