IBに複数の制約セットを設定しましたが、いくつかの状態に応じてそれらをプログラムで切り替えたいと思います。すべてがIBからインストール済みとしてマークされているconstraintsA
アウトレットコレクションと、すべてがIBでアンインストールされるconstraintsB
アウトレットコレクションがあります。
次のように、2つのセットをプログラムで切り替えることができます。
NSLayoutConstraint.deactivateConstraints(constraintsA)
NSLayoutConstraint.activateConstraints(constraintsB)
しかし... ...私はwhenを理解することができません。 viewDidLoad
で一度できるようになっているようですが、それを機能させることはできません。制約を設定した後にview.updateConstraints()
とview.layoutSubviews()
を呼び出してみましたが、役に立ちませんでした。
viewDidLayoutSubviews
に制約を設定すると、すべてが期待どおりに機能することがわかりました。私は2つのことを知りたいと思います...
NSLayoutConstraints
のviewDidLoad
をアクティブおよび非アクティブにしますが、問題はありません。それで動作します。あなたのアプリと私のセットアップの間に違いがあるに違いありません:-)
私は自分の設定について説明します-多分それはあなたにリードを与えることができます:
@IBOutlets
を設定します。ViewController
で、制約を弱くないクラスプロパティに保存します。これは、制約を非アクティブにした後、再アクティブ化できないことがわかったためです-ゼロでした。そのため、無効にすると削除されるようです。NSLayoutConstraint.deactivate/activate
を使用するのではなく、代わりにconstraint.active = YES
/NO
を使用します。view.layoutIfNeeded()
を呼び出します。@properties
を確認し、weak
をstrong
に置き換えてください。
active = NO
がself.yourConstraint = nil
を設定したために、self.yourConstraint
を再び使用できなくなったことがあるためです。
override func viewDidLayoutSubviews() {
// do it here, after constraints have been materialized
}
あなたが経験している問題は、AFTER viewDidLoad()
が呼び出されるまで、ビューに制約が追加されないことが原因であると考えています。いくつかのオプションがあります:
A)レイアウト制約をIBOutletに接続し、これらの参照によってコード内でそれらにアクセスできます。 viewDidLoad()
が開始する前にアウトレットが接続されているため、制約にアクセスできるはずであり、そこで引き続きアクティブ化および非アクティブ化できます。
B) UIViewのconstraints()
関数を使用してさまざまな制約にアクセスする場合は、viewDidLayoutSubviews()
がキックオフしてそこで実行されるのを待つ必要があります。これは、nibからView Controllerを作成した後の最初のポイントですインストール済みの制約があります。完了したら、layoutIfNeeded()
を呼び出すことを忘れないでください。これには、適用する変更がある場合にレイアウトパスが2回実行されるという欠点があり、無限ループがトリガーされる可能性がないことを確認する必要があります。
簡単な警告:無効な制約は、constraints()
method!これは、後で再び有効にするために制約を無効にした場合、その参照を保持する必要があることを意味します。
C)ストーリーボードのアプローチを忘れて、代わりに手動で制約を追加できます。 viewDidLoad()
でこれを行っているので、その場でレイアウトを変更するのではなく、オブジェクトの存続期間全体で一度だけ行うことを意図していると思います。したがって、これは許容できる方法である必要があります。
priority
プロパティを調整して、「有効」および「無効」にすることもできます(有効にする場合は750、無効にする場合は250)。何らかの理由で、active
BOOLを変更しても、UIに影響はありませんでした。 layoutIfNeeded
の必要はなく、viewDidLoadまたはその後いつでも設定および変更できます。
未使用の制約を無効にする適切な時間:
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
self.myLittleConstraint.active = NO;
}
viewWillLayoutSubviews
が複数回呼び出される可能性があるので、ここでは重い計算は必要ないことに注意してください
注:いくつかの制約を後でリアクティブにしたい場合は、常にstrong
参照を保存してください。
- (void)updateConstraints
(Objective C)のオーバーライドで通常ごとに制約を設定し、初期およびアクティブな制約にstrong
参照を使用する限り、制約を設定します。また、ビューサイクルの他の場所で必要なものを非アクティブ化および/またはアクティブ化し、layoutIfNeeded
を呼び出しても問題はありません。
主なことは、最初の初期化とレイアウトの後にupdateConstraints
sを呼び出す限り、updateConstraint
のオーバーライドを絶えず再利用せず、制約のアクティベーションを分離することではありません。その後、ビューサイクルのどこで問題になるようです。
ビューが作成されると、次のライフサイクルメソッドが順番に呼び出されます。
さて、質問に。
- なぜこの動作が発生するのですか?
回答:viewDidLoad
のビューに制約を設定しようとすると、ビューには境界がないため、制約を設定できません。ビューの境界が確定されるのは、viewDidLayoutSubviews
の後でのみです。
- ViewDidLoadから制約をアクティブ化/非アクティブ化することは可能ですか?
回答:いいえ。理由は上記で説明しました。