web-dev-qa-db-ja.com

UIStackView-スタックビューを非表示にするときのレイアウト制約の問題

私のアプリには2つの画面があります。

  1. TableViewVC(ここにはスタックビューはありません)

  2. 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から完全に削除されます。

それはまだ完璧ではありません。なぜなら、隠されているはずのビューを垣間見ることがあるからです。画面上で本当に素早く点滅して消えます。しかし、これは非常に速く起こります。

これが警告を取り除く理由に関する提案はありますか?また、これを完全に機能させるための改善方法に関する提案はありますか?ありがとう!

22
JEL

変更後にスーパーを呼び出して、これを試しましたか?

override func viewWillAppear() {

    self.nameLabel.text = "John"

    self.summaryStackView.hidden = true
    self.combinedStackView.hidden = true

    super.viewWillAppear()
}
0
adamek

私は同じ問題を抱えていたので、最初に非表示にしたビューの高さの制約の優先順位を999にすることで修正しました。

enter image description here

問題は、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)]>"
)

高さの制約の優先度を低くすると、この問題が解決します。

81
Raphael

これは、ネストされたスタックビューの非表示に関する既知の問題です。

この問題には基本的に3つの解決策があります。

  1. 間隔を0に変更しますが、前の間隔値を覚えておく必要があります。
  2. innerStackView.removeFromSuperview()を呼び出しますが、スタックビューを挿入する場所を覚えておく必要があります。
  3. スタックビューを少なくとも1つの999制約でUIViewにラップします。例えば。トップ、リーディング、トレーリング@ 1000、ボトム@ 999。

私の意見では、3番目のオプションが最適です。この問題の詳細、発生の理由、さまざまなソリューション、ソリューション3の実装方法については、 同様の質問に対する私の答え を参照してください。

24
Senseful

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:このメソッドは、提供されたビューをスタックのArrangedSubviews配列から削除します。ビューの位置とサイズは、スタックビューで管理されなくなります。ただし、このメソッドは、提供されたビューをスタックのサブビュー配列から削除しません。したがって、ビューは引き続きビュー階層の一部として表示されます。

スタックのremoveArrangedSubview:メソッドを呼び出した後にビューが画面に表示されないようにするには、ビューのremoveFromSuperviewメソッドを呼び出してサブビュー配列から明示的にビューを削除するか、ビューのhiddenプロパティをYESに設定します。

8
Dinesh

UIViewStackが非表示の場合、UIStackViewの間隔プロパティにゼロ以外の値がある場合、UIStackViewによって自動的に生成された制約は、多くのUISV非表示、UISV間隔、UISVキャンバス接続警告をスローします。

これはあまり意味がなく、ほぼ間違いなくフレームワークのバグです。私が使用する回避策は、コンポーネントを非表示にするときに間隔をゼロに設定することです。

if hideStackView {
    myStackView.hidden = true
    myStackView.spacing = CGFloat(0)
} else {
    myStackView.hidden = false
    myStackView.spacing = CGFloat(8)
}
2

Interface Builderで非表示プロパティを設定すると、ネストされたUIStackViewsがこの動作を示すことがわかりました。私の解決策は、すべてを✨InterfaceBuilderで非表示にしないように設定し、viewWillAppearで選択的に非表示にすることでした。

1
Jacob Jennings

非表示コマンドをtraitCollectionDidChangeに入れることで修正しました。

override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
    super.traitCollectionDidChange(previousTraitCollection)
    self.item.hidden = true
}
1
aqubi

したがって、これはユーザーの0.000001%のみを助けるかもしれませんが、おそらくこれは境界の問題のクリップです。

最近UICollectionViewCellで作業しているときにこれに遭遇しました。コンテンツビューとして扱っていたビューの境界にクリップをチェックするのを忘れていました。 IBでUITableViewCellを作成すると、デフォルトで境界へのクリップを含むコンテンツビューが設定されます。

ポイントは、状況によっては、フレームとクリッピングを使用して意図した効果を達成できる場合があることです。

1
Joe Susnick

すべての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"
    }
}
1
tigaris

このエラーは非表示に関するものではなく、あいまいな制約に関するものです。ビューに曖昧な制約があってはなりません。プログラムで追加する場合は、追加する制約とそれらがどのように連携するかを正確に理解する必要があります。プログラムで追加せず、ストーリーボードまたはxibを使用するのが適切な場合は、制約エラーや警告がないことを確認してください。

UPD:かなり複雑なビュー構造があります。制約を見ることなく、何が正確に間違っているかを言うのは難しいです。ただし、ビュー階層を構築して、ビューを1つずつ徐々に追加し、設計時/実行時の警告がないことを確認することをお勧めします。スクロールビューは、正しく処理しないと、さらに複雑なレベルになります。スクロールビューで制約を使用する方法を確認します。とにかく、他のすべてのタイミングハックは解決策ではありません。

0
Davyd Geyl

ネストされたUIStackViewのすべての非表示ビューを配列に保存し、それらをスーパービューおよび配置されたサブビューから削除することにより、これを行いました。それらを再び表示させたいときは、配列をループ処理して再度追加しました。これが最初のステップでした。

2番目のステップは、ネストされたUIStackViewのビューをスーパービューから削除した後、親UIStackViewが高さを調整しないままです。これを修正するには、ネストされたUIStackViewを削除し、すぐに再度追加します。

UIStackView *myStackView;
NSUInteger positionOfMyStackView = [parentStackView indexOfObject:myStackView];
[parentStackView removeArrangedSubview:myStackView];
[myStackView removeFromSuperview];
[parentStackView insertArrangedSubview:myStackView atIndex:positionOfMyStackView];
0
sp00ky

viewWillLayoutSubviews() {}に非表示コマンドを配置します

0
Tim