UIStackViewの「行」がつぶされると、AutoLayout
警告がスローされます。ただし、これらは正常に表示され、これらの種類のログ以外に問題はありません。
同時に制約を満たすことができません。おそらく、次のリストにある制約の少なくとも1つは、望ましくないものです。これを試してください:(1)各制約を見て、予期しないものを見つけてください。 (2)不要な制約を追加したコードを見つけて修正します。 (注:理解できない
NSAutoresizingMaskLayoutConstraints
が表示されている場合は、UIView
プロパティのドキュメントを参照してくださいtranslatesAutoresizingMaskIntoConstraints
)(
そのため、これをどのように修正するかはまだわかりませんが、単にうっとうしいこと以外に何も壊さないようです。
誰もそれを解決する方法を知っていますか?興味深いことに、レイアウト制約には'UISV-hiding'というタグが頻繁に付けられます。これは、サブインスタンスまたはこのインスタンスの何かの最小高さを無視する必要があることを示していますか?
この問題は、サブビューを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.
私がやろうとしていたことは、UIView
内にUIStackView
を配置することで、各エッジにUISegmentedControl
のインセットが8ポイント挿入されていました。
非表示に設定すると、コンテナビューの高さをゼロに制限しようとしますが、上から下に一連の制約があるため、競合が発生しました。
この問題を解決するために、必要に応じてUISV-hiding
制約が優先されるように、8ptの上位および下位の制約の優先度を1000から999に変更しました。
私は解決が容易ではない同様の問題を抱えていました。私の場合、スタックビューにスタックビューが埋め込まれていました。内部UIStackViewには、2つのラベルと0以外の間隔が指定されていました。
AddArrangedSubview()を呼び出すと、次のような制約が自動的に作成されます。
V:|[innerStackView]| | = outerStackView
V:|[label1]-(2)-[label2]| | = innerStackView
InnerStackViewを非表示にしようとすると、あいまいな制約の警告が表示されます。
理由を理解するために、最初に、innerStackView.spacing
が0
と等しいときに、このが発生しない理由を見てみましょう。 innerStackView.hidden = true
を呼び出すと、@ liamnicholsは正しかった... outerStackView
はこの呼び出しを魔法のようにインターセプトし、0
heightUISV-hiding優先度1000で制約します(必須)。おそらく、これは、UIView.animationWithDuration()
ブロック内で非表示のコードが呼び出された場合に、スタックビューの要素をビュー外でアニメーション化できるようにするためです。残念ながら、この制約が追加されるのを防ぐ方法はないようです。それでも、次のことが発生するため、「制約を同時に満たすことができません」(USSC)警告は表示されません。
これらの4つの制約が満たされることは明らかです。スタックビューは、すべてを0の高さのピクセルに単純化します。
バグのある例に戻り、spacing
を2
に設定すると、次の制約があります。
スタックビューの高さを両方とも0ピクセルにすることはできず、その内容を2ピクセルにすることもできません。制約を満たせません。
注:より簡単な例でこの動作を確認できます。 UIViewをスタックビューに配置されたサブビューとして追加するだけです。次に、そのUIViewに高さ制限を1000の優先度で設定します。それで、hideを呼び出してみてください。
注:何らかの理由で、これはスタックビューがUICollectionViewCellまたはUITableViewCellのサブビューである場合にのみ発生しました。ただし、内部スタックビューを非表示にした後、次の実行ループでinnerStackView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
を呼び出すことにより、セル外でこの動作を再現できます。
注:UIView.performWithoutAnimationsでコードを実行しようとしても、スタックビューには高さ0の制約が追加され、USSC警告が発生します。
この問題には少なくとも3つの解決策があります。
spacing
を0に変更します。これは迷惑なのは、コンテンツを再度表示するたびにプロセスを元に戻す(および元の間隔を記憶する)必要があるためです。removeFromSuperview
を呼び出します。プロセスを逆にすると、覚えておく必要があるため、これはさらに面倒ですwhere削除されたアイテムを挿入します。 removeArrangedSubviewを呼び出して非表示にするだけで最適化できますが、実行する必要のある簿記がたくさんあります。spacing
を持つ)をラップします。少なくとも1つの制約を不要な優先度(999以下)として指定します。これは、簿記を行う必要がないため、最適なソリューションです。この例では、スタックビューとラッパービューの間に1000のトップ、リーディング、トレーリングの制約を作成し、スタックビューの下部からラッパービューに999の制約を作成しました。この方法では、外側のスタックビューが高さゼロの制約を作成するときに、999制約が壊れており、USSC警告は表示されません。 (注:これは、 ICollectionViewCellサブクラスのcontentView.translatesAutoResizingMaskToConstraintsをfalse
)に設定する必要がある場合の解決策に似ています要約すると、この動作が発生する理由は次のとおりです。
Appleが(1)制約の優先度(特にスペーサー)を指定できるか、(2)自動UISV- hiding制約により、この問題は簡単に解決されます。
ほとんどの場合、このエラーは、競合を排除するために制約の優先順位を下げることで解決できます。
ビューを非表示に設定すると、UIStackview
はそれをアニメーション化しようとします。その効果が必要な場合は、制約が競合しないように適切な優先度を設定する必要があります(多くの人が上記で提案したように)。
ただし、アニメーションを気にしない(おそらくViewDidLoadで非表示にしている)場合は、removeFromSuperview
を単純化できます。見る。
埋め込みスタックビューでも同じエラーが発生しましたが、実行時にはすべて正常に機能していました。
親スタックビューを非表示にする前に、最初にすべてのサブスタックビューを非表示にする(isHidden = true
を設定する)ことで制約エラーを解決しました。
これを行うと、サブアレンジされたビューを削除して、それらを再度追加する必要がある場合に備えてインデックスを維持する複雑さがなくなりました。
お役に立てれば。
まず、他の人が示唆しているように、制御できる制約、つまりUIStackViewに固有の制約が優先度999に設定されていないことを確認して、ビューが非表示になったときにオーバーライドできるようにします。
それでも問題が発生する場合は、非表示のStackViewの間隔が原因である可能性があります。 私の解決策は、スペーサーとしてUIViewを追加し、UIStackViewの間隔をゼロに設定することでした。次に、View.heightまたはView.width制約(垂直または水平スタックに応じて)をStackViewの間隔に設定します。
次に、新しく追加されたビューのコンテンツハグとコンテンツ圧縮抵抗の優先順位を調整します。親StackViewの分布も変更する必要がある場合があります。
上記のすべては、Interface Builderで実行できます。さらに、新しく追加されたビューの一部をプログラムで非表示/非表示解除して、不要な間隔を空ける必要がある場合があります。
最近、UIStackView
を非表示にするときに、自動レイアウトエラーに取り組みました。 UIViews
で大量のブックキーピングとラッピングスタックを行うのではなく、parentStackView
用のアウトレットと、非表示/再表示したい子供用のアウトレットを作成することにしました。
@IBOutlet weak var parentStackView: UIStackView!
@IBOutlet var stackViewNumber1: UIStackView!
@IBOutlet var stackViewNumber2: UIStackView!
ストーリーボードでは、私のparentStackは次のようになります。
これには4人の子があり、それぞれの子の内部には多数のスタックビューがあります。スタックビューを非表示にするときに、スタックビューでもあるUI要素がある場合、自動レイアウトエラーのストリームが表示されます。非表示にするのではなく、削除することを選択しました。
私の例では、parentStackViews
には4つの要素の配列が含まれています:上部スタックビュー、StackViewNumber1、スタックビュー番号2、および停止ボタン。 arrangedSubviews
のインデックスは、それぞれ0、1、2、3です。隠したいときは、parentStackView's
arrangedSubviews
配列から単純に削除します。弱くないので、メモリ内に残り、後で希望するインデックスに戻すことができます。私はそれを再初期化していないので、必要になるまでハングアウトしますが、メモリを膨張させません。
基本的に、次のことができます...
1)親スタックおよび非表示/再表示する子のIBOutletsをストーリーボードにドラッグします。
2)非表示にする場合は、parentStackView's
arrangedSubviews
配列から非表示にするスタックを削除します。
3)UIView.animateWithDuration
でself.view.layoutIfNeeded()
を呼び出します。
最後の2つのstackViewはweak
ではないことに注意してください。それらを再表示するときのために、それらを保持する必要があります。
StackViewNumber2を非表示にしたいとしましょう:
parentStackView.removeArrangedSubview(stackViewNumber2)
stackViewNumber2.removeFromSuperview()
次に、アニメーション化します。
UIView.animate(withDuration: 0.25,
delay: 0,
usingSpringWithDamping: 2.0,
initialSpringVelocity: 10.0,
options: [.curveEaseOut],
animations: {
self.view.layoutIfNeeded()
},
completion: nil)
後でstackViewNumber2
を「再表示」したい場合は、必要なparentStackView
arrangedSubViews
インデックスに挿入して、更新をアニメートするだけです。
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()
を使用してアニメーションなしで更新できます。
@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()
を使用します。
スタックビュー全体を一度に非表示にしたかったのですが、OPと同じエラーが表示されていたため、修正されました。
for(UIView *currentView in self.arrangedSubviews){
for(NSLayoutConstraint *currentConstraint in currentView.constraints){
[currentConstraint setPriority:999];
}
}
上記の問題の根本に対して、賢明な回答が優れた答えを提供してくれたので、すぐに解決策に進みます。
必要なことは、すべてのstackView制約の優先順位を1000未満に設定することです(999が作業を行います)。たとえば、stackViewが左、右、上、および下からそのスーパービューに制限されている場合、4つのすべての制約の優先順位は1000未満でなければなりません。
特定のサイズクラス(例:wCompact hRegular)で作業中に制約を作成し、別のサイズクラス(例:wAny hAny)に切り替えたときに複製を作成した可能性があります。さまざまなサイズのクラスのUIオブジェクトの制約を確認し、制約に異常があるかどうかを確認します。衝突する制約を示す赤い線が表示されます。評判ポイントが10ポイントになるまで写真を撮れません:/
高さ制限のあるボタンの列がありました。これは、1つのボタンが非表示のときに発生します。そのボタンの高さの制約の優先度を999に設定すると、問題が解決しました。