私のアプリには2つの画面があります。
TableViewVC(ここにはスタックビューはありません)
DetailVC(ここですべてのネストされたスタックビュー。写真のリンクを参照してください: Nested StackViews Picture )-注、これらのスタックビューにはラベルと画像があります。
TableViewでセルを押すと、TableViewVCからDetailVCに情報が渡されます。問題は、DetailVCで特定のUIStackViewsを非表示にすることです。そのため、これを実現するためにDetailVCでこのコードを作成します。
override func viewDidLoad() {
super.viewDidLoad()
self.nameLabel.text = "John"
self.summaryStackView.hidden = true
self.combinedStackView.hidden = true
}
すべてが素晴らしく見えますが、Xcodeはruntimeでのみ多くの警告を出します。アプリが実行されていない場合、ストーリーボードには警告はありません。エラーの画像については、リンクを参照してください: エラーの画像
基本的に、それは多くのUISV非表示、UISV間隔、UISVキャンバス接続エラーです。 viewDidAppear
で同じスタックビューを非表示にすると、これらのエラーはなくなりますが、非表示になるはずだったものがフラッシュされて非表示になります。ユーザーはビューを短時間表示した後、非表示にします。
リンクの代わりに実際に写真を投稿できないことを申し訳なく思っていますが、まだ投稿できません。
これを修正する方法に関する提案はありますか?これは、私が実際にアプリストアに起動したいアプリのためのものです。これは私の最初のアプリなので、どんな助けでもいいでしょう。
編集/更新1:
DetailVCと呼ばれる2番目の画面内に配置したこのコードで小さな回避策を見つけました:
// Function I use to delay hiding of views
func delay(delay: Double, closure: ()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
// Hide the 2 stack views after 0.0001 seconds of screen loading
override func awakeFromNib() {
delay(0.001) { () -> () in
self.summaryStackView.hidden = true
self.combinedStackView.hidden = true
}
}
// Update view screen elements after 0.1 seconds in viewWillAppear
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
delay(0.1) { () -> () in
self.nameLabel.text = "John"
}
}
これにより、レイアウトの制約に関する警告がXcodeから完全に削除されます。
それはまだ完璧ではありません。なぜなら、隠されているはずのビューを垣間見ることがあるからです。画面上で本当に素早く点滅して消えます。しかし、これは非常に速く起こります。
これが警告を取り除く理由に関する提案はありますか?また、これを完全に機能させるための改善方法に関する提案はありますか?ありがとう!
変更後にスーパーを呼び出して、これを試しましたか?
override func viewWillAppear() {
self.nameLabel.text = "John"
self.summaryStackView.hidden = true
self.combinedStackView.hidden = true
super.viewWillAppear()
}
私は同じ問題を抱えていたので、最初に非表示にしたビューの高さの制約の優先順位を999にすることで修正しました。
問題は、stackviewが非表示のビューに0の高さ制約を適用することです。これは他の高さ制約と競合します。これはエラーメッセージでした。
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:0x7fa3a5004310 V:[App.DummyView:0x7fa3a5003fd0(40)]>",
"<NSLayoutConstraint:0x7fa3a3e44190 'UISV-hiding' V:[App.DummyView:0x7fa3a5003fd0(0)]>"
)
高さの制約の優先度を低くすると、この問題が解決します。
これは、ネストされたスタックビューの非表示に関する既知の問題です。
この問題には基本的に3つの解決策があります。
innerStackView.removeFromSuperview()
を呼び出しますが、スタックビューを挿入する場所を覚えておく必要があります。私の意見では、3番目のオプションが最適です。この問題の詳細、発生の理由、さまざまなソリューション、ソリューション3の実装方法については、 同様の質問に対する私の答え を参照してください。
UIStackViewのremoveArrangedSubviewおよびremoveFromSuperviewプロパティを使用できます。
Objective-Cの場合:
[self.topStackView removeArrangedSubview:self.summaryStackView];
[self.summaryStackView removeFromSuperview];
[self.topStackView removeArrangedSubview:self.combinedStackView];
[self.combinedStackView removeFromSuperview];
From Apple UIStackView Documentation:( https://developer.Apple.com/library/ios/documentation/UIKit/Reference/UIStackView_Class_Reference/#//Apple_ref/occ/instm/ UIStackView/removeArrangedSubview :)
スタックビューは、arrangedSubviews配列にビューが追加、削除、または挿入されるたびに、レイアウトを自動的に更新します。
スタックのremoveArrangedSubview:メソッドを呼び出した後にビューが画面に表示されないようにするには、ビューのremoveFromSuperviewメソッドを呼び出してサブビュー配列から明示的にビューを削除するか、ビューのhiddenプロパティをYESに設定します。
UIViewStackが非表示の場合、UIStackViewの間隔プロパティにゼロ以外の値がある場合、UIStackViewによって自動的に生成された制約は、多くのUISV非表示、UISV間隔、UISVキャンバス接続警告をスローします。
これはあまり意味がなく、ほぼ間違いなくフレームワークのバグです。私が使用する回避策は、コンポーネントを非表示にするときに間隔をゼロに設定することです。
if hideStackView {
myStackView.hidden = true
myStackView.spacing = CGFloat(0)
} else {
myStackView.hidden = false
myStackView.spacing = CGFloat(8)
}
Interface Builderで非表示プロパティを設定すると、ネストされたUIStackViewsがこの動作を示すことがわかりました。私の解決策は、すべてを✨InterfaceBuilderで非表示にしないように設定し、viewWillAppearで選択的に非表示にすることでした。
非表示コマンドをtraitCollectionDidChangeに入れることで修正しました。
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
self.item.hidden = true
}
したがって、これはユーザーの0.000001%のみを助けるかもしれませんが、おそらくこれは境界の問題のクリップです。
最近UICollectionViewCell
で作業しているときにこれに遭遇しました。コンテンツビューとして扱っていたビューの境界にクリップをチェックするのを忘れていました。 IBでUITableViewCell
を作成すると、デフォルトで境界へのクリップを含むコンテンツビューが設定されます。
ポイントは、状況によっては、フレームとクリッピングを使用して意図した効果を達成できる場合があることです。
すべてのUIStackView.hiddenコードをviewDidLoadからviewDidAppearに移動すると、制約違反の問題はなくなりました。私の場合、競合する制約はすべて自動生成されたため、優先順位を調整する方法はありません。
また、このコードを使用してよりきれいにしました。
UIView.animateWithDuration(0.5) {
self.deliveryGroup.hidden = self.shipVia != "1"
}
編集:
また、デバイスが回転したときに再び発生するのを防ぐために、次のコードが必要でした:
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
self.deliveryGroup.hidden = false
coordinator.animateAlongsideTransition(nil) {
context in
self.deliveryGroup.hidden = self.shipVia != "1"
}
}
このエラーは非表示に関するものではなく、あいまいな制約に関するものです。ビューに曖昧な制約があってはなりません。プログラムで追加する場合は、追加する制約とそれらがどのように連携するかを正確に理解する必要があります。プログラムで追加せず、ストーリーボードまたはxibを使用するのが適切な場合は、制約エラーや警告がないことを確認してください。
UPD:かなり複雑なビュー構造があります。制約を見ることなく、何が正確に間違っているかを言うのは難しいです。ただし、ビュー階層を構築して、ビューを1つずつ徐々に追加し、設計時/実行時の警告がないことを確認することをお勧めします。スクロールビューは、正しく処理しないと、さらに複雑なレベルになります。スクロールビューで制約を使用する方法を確認します。とにかく、他のすべてのタイミングハックは解決策ではありません。
ネストされたUIStackViewのすべての非表示ビューを配列に保存し、それらをスーパービューおよび配置されたサブビューから削除することにより、これを行いました。それらを再び表示させたいときは、配列をループ処理して再度追加しました。これが最初のステップでした。
2番目のステップは、ネストされたUIStackViewのビューをスーパービューから削除した後、親UIStackViewが高さを調整しないままです。これを修正するには、ネストされたUIStackViewを削除し、すぐに再度追加します。
UIStackView *myStackView;
NSUInteger positionOfMyStackView = [parentStackView indexOfObject:myStackView];
[parentStackView removeArrangedSubview:myStackView];
[myStackView removeFromSuperview];
[parentStackView insertArrangedSubview:myStackView atIndex:positionOfMyStackView];
viewWillLayoutSubviews() {}
に非表示コマンドを配置します