101

UIStackView の「行」が押しつぶされると、AutoLayout警告がスローされます。ただし、それらは正常に表示され、次の種類のログ以外に問題はありません。

制約を同時に満たすことができません。おそらく、次のリストの制約の少なくとも 1 つが望ましくないものです。これを試してみてください: (1) 各制約を見て、どれが予期しないものかを把握してみてください。(2) 不要な制約を追加したコードを見つけて修正します。(注:NSAutoresizingMaskLayoutConstraintsよくわからない場合は、UIViewプロパティのドキュメントを参照してくださいtranslatesAutoresizingMaskIntoConstraints) (

したがって、これを修正する方法はまだわかりませんが、迷惑なだけで何も壊れていないようです.

誰もそれを解決する方法を知っていますか? 興味深いことに、レイアウトの制約は'UISV-hiding'で頻繁にタグ付けされており、このインスタンスではサブビューまたは何かの高さの最小値を無視する必要があることを示していますか?

4

14 に答える 14

211

この問題が発生するのは、サブビューを内部UIStackViewから非表示に設定すると、アニメーション化するために最初に高さがゼロに制限されるためです。

次のエラーが発生しました。

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.

私がやろうとしていたのは、各エッジに 8 ポイントのインセットを含むUIViewを私の中に配置することでした。UIStackViewUISegmentedControl

非表示に設定すると、コンテナー ビューを高さゼロに制限しようとしますが、上から下に一連の制約があるため、競合が発生しました。

この問題を解決するために、8pt の上下の制約の優先度を 1000 から 999 に変更して、UISV-hiding必要に応じて制約が優先されるようにしました。

于 2015-10-01T11:02:37.640 に答える
57

私は解決が容易ではない同様の問題を抱えていました。私の場合、スタック ビューにスタック ビューが埋め込まれていました。内部 UIStackView には 2 つのラベルがあり、ゼロ以外の間隔が指定されていました。

addArrangedSubview() を呼び出すと、次のような制約が自動的に作成されます。

V:|[innerStackView]|              | = outerStackView

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

innerStackView を非表示にしようとすると、あいまいな制約の警告が表示されます。

その理由を理解するために、が に等しいときにこれが起こらない理由をまず見てみましょう。を呼び出すと、@liamnichols は正しかった...は魔法のようにこの呼び出しをインターセプトし、優先度 1000 (必須)の高さUISV 非表示制約を作成します。おそらく、これは、非表示のコードがブロック内で呼び出された場合に、スタック ビュー内の要素をアニメーション化してビューの外に出せるようにするためです。残念ながら、この制約が追加されないようにする方法はないようです。それでも、次のことが発生するため、「制約を同時に満たすことができません」(USSC) 警告は表示されません。innerStackView.spacing0innerStackView.hidden = trueouterStackView0UIView.animationWithDuration()

  1. label1 の高さは 0 に設定されています
  2. 2 つのラベル間の間隔は既に 0 として定義されています
  3. label2 の高さは 0 に設定されています
  4. innerStackView の高さは 0 に設定されています

これら 4 つの制約を満たすことができることは明らかです。スタック ビューは、単純にすべてを高さ 0 のピクセルに滑らかにします。

バグのある例に戻ると、 を に設定するspacing2、次の制約が適用されます。

  1. label1 の高さは 0 に設定されています
  2. 2 つのラベル間の間隔は、優先度 1000 で高さ 2 ピクセルとして、スタック ビューによって自動的に作成されました。
  3. label2 の高さは 0 に設定されています
  4. innerStackView の高さは 0 に設定されています

スタック ビューの高さを 0 ピクセルにすることも、その内容を 2 ピクセルにすることもできません。制約を満たすことができません。

注: この動作は、より単純な例で確認できます。UIView を配置されたサブビューとしてスタック ビューに追加するだけです。次に、その UIView に高さの制約を 1000 の優先度で設定します。これで hide を呼び出してみてください。

注: 何らかの理由で、これは私のスタック ビューが UICollectionViewCell または UITableViewCell のサブビューである場合にのみ発生しました。innerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)ただし、内側のスタック ビューを非表示にした後で次の実行ループを呼び出すことで、セルの外側でこの動作を再現できます。

注: UIView.performWithoutAnimations でコードを実行しようとしても、スタック ビューは引き続き 0 高さ制約を追加し、USSC 警告が発生します。


この問題には、少なくとも 3 つの解決策があります。

  1. スタック ビューで要素を非表示にする前に、それがスタック ビューかどうかを確認し、そうである場合はspacingを 0に変更します。これは、コンテンツを再度表示するたびにプロセスを逆にする必要があるため (元の間隔を覚えておく必要があるため) 面倒です。
  2. スタック ビューで要素を非表示にする代わりに、 を呼び出しますremoveFromSuperviewプロセスを逆にすると、削除したアイテムをどこに挿入するかを覚えておく必要があるため、これはさらに面倒です。removeArrangedSubview を呼び出してから非表示にするだけで最適化できますが、まだ実行する必要がある多くの簿記があります。
  3. ネストされたスタック ビュー (ゼロ以外の値を持つspacing) を UIView にラップします。必須でない優先度 (999 以下) として少なくとも 1 つの制約を指定します。簿記を行う必要がないため、これが最適なソリューションです。この例では、スタック ビューとラッパー ビューの間で 1000 で上、先頭、および末尾の制約を作成し、スタック ビューの下部からラッパー ビューまで 999 の制約を作成しました。このように、外側のスタック ビューが高さゼロの制約を作成すると、999 の制約が壊れ、USSC 警告が表示されなくなります。(注: これは、UICollectionViewCell サブクラスの contentView.translatesAutoResizingMaskToConstraints を に設定する必要がある場合falseの解決策に似ています)

要約すると、この動作が発生する理由は次のとおりです。

  1. 管理されたサブビューをスタック ビューに追加すると、Apple は自動的に 1000 の優先度制約を作成します。
  2. スタック ビューのサブビューを非表示にすると、高さ 0 の制約が Apple によって自動的に作成されます。

Apple が (1) 制約 (特にスペーサー) の優先順位を指定できるようにするか、(2) 自動UISV 非表示制約をオプトアウトできるようにすると、この問題は簡単に解決されます。

于 2016-06-27T23:17:48.450 に答える
2

ビューを非表示に設定すると、 はUIStackviewそれをアニメーション化しようとします。その効果が必要な場合は、制約に適切な優先順位を設定して、競合しないようにする必要があります (上記で多くの人が示唆しているように)。

ただし、アニメーションを気にしない場合 (おそらく ViewDidLoad で非表示にしている場合)removeFromSuperviewは、同じ効果を持つ単純化できますが、ビューと共に削除されるため、制約に関する問題はありません。

于 2016-09-05T18:32:50.020 に答える
1

まず、他の人が示唆しているように、制御できる制約、つまり UIStackView に固有の制約ではなく、優先度 999 に設定されていることを確認して、ビューが非表示のときにオーバーライドできるようにします。

問題が解決しない場合は、非表示の StackView の間隔が原因である可能性があります。 私の解決策は、UIView をスペーサーとして追加し、UIStackView の間隔をゼロに設定することでした。 次に、View.height または View.width の制約 (垂直スタックまたは水平スタックに応じて) を StackView の間隔に設定します。

次に、新しく追加されたビューのコンテンツ ハグとコンテンツ圧縮耐性の優先順位を調整します。親 StackView の配布も変更する必要がある場合があります。

上記のすべては、Interface Builder で実行できます。不要なスペースがないように、新しく追加されたビューの一部をプログラムで非表示/非表示にする必要がある場合があります。

于 2016-09-11T00:26:42.607 に答える
1

@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、を使用しますstackView.wrapped()

于 2016-08-04T18:23:10.673 に答える
1

I experienced the same errors with embedded Stack Views, though everything worked fine at runtime.

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

Doing this did not have all the complexity of removing sub arranged views, maintaining an index for when needing to add them back.

Hope this helps.

于 2017-04-23T19:09:46.477 に答える
1

Senseful は上記の問題の根本に優れた回答を提供してくれたので、解決策に直行します。

すべての stackView 制約の優先度を 1000 より低く設定するだけです (999 で十分です)。たとえば、stackView がそのスーパービューに対して左、右、上、および下に制約されている場合、4 つの制約すべての優先度を 1000 より低くする必要があります。

于 2019-02-25T08:24:57.850 に答える
0

高さ制限のあるボタンの列がありました。これは、1 つのボタンが非表示になっている場合に発生します。そのボタンの高さの制約の優先度を 999 に設定すると、問題が解決しました。

于 2016-10-07T12:25:37.287 に答える
-2

このエラーは UIStackView とは関係ありません。これは、優先順位が同じ競合制約がある場合に発生します。たとえば、ビューの幅が 100 であるという制約があり、同時にビューの幅がコンテナーの 25% であるという別の制約があるとします。2 つの矛盾する制約があることは明らかです。解決策は、それらを削除することです。

于 2015-09-14T14:49:20.047 に答える
-3

[mySubView removeFromSuperview] で NOP。私はそれが誰かを助けることを願っています:)

于 2016-08-09T04:45:08.773 に答える