web-dev-qa-db-ja.com

レイアウト制約をいつアクティブ化/非アクティブ化できますか?

IBに複数の制約セットを設定しましたが、いくつかの状態に応じてそれらをプログラムで切り替えたいと思います。すべてがIBからインストール済みとしてマークされているconstraintsAアウトレットコレクションと、すべてがIBでアンインストールされるconstraintsBアウトレットコレクションがあります。

次のように、2つのセットをプログラムで切り替えることができます。

NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)

しかし... ...私はwhenを理解することができません。 viewDidLoadで一度できるようになっているようですが、それを機能させることはできません。制約を設定した後にview.updateConstraints()view.layoutSubviews()を呼び出してみましたが、役に立ちませんでした。

viewDidLayoutSubviewsに制約を設定すると、すべてが期待どおりに機能することがわかりました。私は2つのことを知りたいと思います...

  1. なぜこの動作が発生するのですか?
  2. ViewDidLoadから制約をアクティブ化/非アクティブ化することは可能ですか?
87
tybro0103

NSLayoutConstraintsviewDidLoadをアクティブおよび非アクティブにしますが、問題はありません。それで動作します。あなたのアプリと私のセットアップの間に違いがあるに違いありません:-)

私は自分の設定について説明します-多分それはあなたにリードを与えることができます:

  1. アクティブ化/非アクティブ化する必要があるすべての制約に対して@IBOutletsを設定します。
  2. ViewControllerで、制約を弱くないクラスプロパティに保存します。これは、制約を非アクティブにした後、再アクティブ化できないことがわかったためです-ゼロでした。そのため、無効にすると削除されるようです。
  3. あなたのようにNSLayoutConstraint.deactivate/activateを使用するのではなく、代わりにconstraint.active = YES/NOを使用します。
  4. 制約を設定した後、view.layoutIfNeeded()を呼び出します。
161

@propertiesを確認し、weakstrongに置き換えてください

active = NOself.yourConstraint = nilを設定したために、self.yourConstraintを再び使用できなくなったことがあるためです。

40
Leo
override func viewDidLayoutSubviews() {
// do it here, after constraints have been materialized
}
28
Tony Swiftguy

あなたが経験している問題は、AFTER viewDidLoad()が呼び出されるまで、ビューに制約が追加されないことが原因であると考えています。いくつかのオプションがあります:

A)レイアウト制約をIBOutletに接続し、これらの参照によってコード内でそれらにアクセスできます。 viewDidLoad()が開始する前にアウトレットが接続されているため、制約にアクセスできるはずであり、そこで引き続きアクティブ化および非アクティブ化できます。

B) UIViewのconstraints()関数を使用してさまざまな制約にアクセスする場合は、viewDidLayoutSubviews()がキックオフしてそこで実行されるのを待つ必要があります。これは、nibからView Controllerを作成した後の最初のポイントですインストール済みの制約があります。完了したら、layoutIfNeeded()を呼び出すことを忘れないでください。これには、適用する変更がある場合にレイアウトパスが2回実行されるという欠点があり、無限ループがトリガーされる可能性がないことを確認する必要があります。

簡単な警告:無効な制約は、constraints()method!これは、後で再び有効にするために制約を無効にした場合、その参照を保持する必要があることを意味します。

C)ストーリーボードのアプローチを忘れて、代わりに手動で制約を追加できます。 viewDidLoad()でこれを行っているので、その場でレイアウトを変更するのではなく、オブジェクトの存続期間全体で一度だけ行うことを意図していると思います。したがって、これは許容できる方法である必要があります。

14
Ash

priorityプロパティを調整して、「有効」および「無効」にすることもできます(有効にする場合は750、無効にする場合は250)。何らかの理由で、active BOOLを変更しても、UIに影響はありませんでした。 layoutIfNeededの必要はなく、viewDidLoadまたはその後いつでも設定および変更できます。

9
user2387149

未使用の制約を無効にする適切な時間:

-(void)viewWillLayoutSubviews{
    [super viewWillLayoutSubviews];

    self.myLittleConstraint.active = NO;
}

viewWillLayoutSubviewsが複数回呼び出される可能性があるので、ここでは重い計算は必要ないことに注意してください

注:いくつかの制約を後でリアクティブにしたい場合は、常にstrong参照を保存してください。

7
Laszlo

- (void)updateConstraints(Objective C)のオーバーライドで通常ごとに制約を設定し、初期およびアクティブな制約にstrong参照を使用する限り、制約を設定します。また、ビューサイクルの他の場所で必要なものを非アクティブ化および/またはアクティブ化し、layoutIfNeededを呼び出しても問題はありません。

主なことは、最初の初期化とレイアウトの後にupdateConstraintssを呼び出す限り、updateConstraintのオーバーライドを絶えず再利用せず、制約のアクティベーションを分離することではありません。その後、ビューサイクルのどこで問題になるようです。

1
elliotrock

ビューが作成されると、次のライフサイクルメソッドが順番に呼び出されます。

  1. loadView
  2. viewDidLoad
  3. viewWillAppear
  4. viewWillLayoutSubviews
  5. viewDidLayoutSubviews
  6. viewDidAppear

さて、質問に。

  1. なぜこの動作が発生するのですか?

回答:viewDidLoadのビューに制約を設定しようとすると、ビューには境界がないため、制約を設定できません。ビューの境界が確定されるのは、viewDidLayoutSubviewsの後でのみです。

  1. ViewDidLoadから制約をアクティブ化/非アクティブ化することは可能ですか?

回答:いいえ。理由は上記で説明しました。

0
Sumeet