web-dev-qa-db-ja.com

プログラムでビューを作成するときに、自動レイアウト制約を設定する場所

制約が設定されているさまざまな例があります。一部はviewDidLoad/loadViewに設定します(サブビューが追加された後)。その他は、updateViewConstraintsによって呼び出されるメソッドviewDidAppearでそれらを設定します。

updateViewContraintsに制約を設定しようとすると、レイアウトに急激な変化が生じることがあります。ビューが表示されるまでのわずかな遅延。また、このメソッドを使用する場合、既存の制約を最初にクリアする必要がありますか?つまり、[self.view [removeConstraints:self.view.constraints]

76
Heisenberg

viewDidLoad/loadViewに制約を設定しました(iOSを6以上ターゲットにしています)。 updateViewConstraintsは、制約の値を変更するのに便利です。何らかの制約が画面の向きに依存している場合(悪い習慣です)、このメソッドでconstantを変更できます。

セッション中にviewDidLoadに制約を追加することが表示されます「iOSおよびOS Xの自動レイアウトの概要」(WWDC 2012) 39:22。講義中に言われても、ドキュメントには載っていないことの1つだと思います。

UPDATE:View Controllersのリソース管理 :で制約を設定することに言及していることに気付きました。

ストーリーボードを使用するのではなく、プログラムでビューを作成する場合は、View ControllerのloadViewメソッドをオーバーライドして作成します。このメソッドの実装では、次のことを行う必要があります。

(...)

3.自動レイアウトを使用している場合は、ビューの位置とサイズを制御するために作成した各ビューに十分な制約を割り当てます。それ以外の場合は、viewWillLayoutSubviewsメソッドとviewDidLayoutSubviewsメソッドを実装して、ビュー階層内のサブビューのフレームを調整します。 「View Controllerのビューのサイズ変更」を参照してください。

更新2:WWDC 2015期間中 Appleが新しい説明を行った of updateConstraints and updateViewConstraints推奨される使用法:

実際、これはビューが次のレイアウトパスに間に合うように制約を変更する機会を持つ方法ですが、実際には必要ではないことがよくあります。

初期制約の設定はすべて、理想的にはInterface Builder内で行う必要があります。

または、プログラムで制約を割り当てる必要があることが本当にわかった場合は、viewDidLoadのような場所がはるかに優れています。

更新の制約は、実際には定期的に繰り返す必要がある作業専用です。

また、制約を変更する必要があるとわかったときに、制約を変更することは非常に簡単です。一方、そのロジックをそれに関連する他のコードから切り離し、後で実行される別のメソッドに移動すると、コードを追跡するのが非常に難しくなるため、管理が難しくなります、他の人が理解するのはずっと難しくなります。

それでは、いつ更新制約を使用する必要がありますか?

まあ、それはパフォーマンスに要約されます。

制約を適切に変更するだけでは遅すぎる場合は、制約の更新が役立つ場合があります。

更新制約内の制約の変更は、実際には他の時間に制約を変更するよりも速いことがわかります。

その理由は、エンジンがこのパスで発生するすべての制約の変更をバッチとして扱うことができるためです。

102
Arek Holko

BOOLを作成して、-updateConstraints of UIView(または-updateViewConstraints、UIViewControllerの場合)。

-[UIView updateConstraints] :(Appleドキュメント)

制約自体を設定するカスタムビューは、このメソッドをオーバーライドすることで設定する必要があります。

両方 -updateConstraintsおよび-updateViewConstraintsは、ビューの存続期間中に複数回呼び出される場合があります。 (たとえば、ビューでsetNeedsUpdateConstraintsを呼び出すと、これが発生します。)そのため、重複した制約の作成とアクティブ化を防ぐ必要があります。BOOLを使用して特定の制約設定のみを実行する一度、または新しい制約を作成およびアクティブ化する前に、既存の制約を非アクティブ化/削除してください。

例えば:

  - (void)updateConstraints {  // for view controllers, use -updateViewConstraints

         if (!_hasLoadedConstraints) {
              _hasLoadedConstraints = YES;
             // create your constraints
         }
         [super updateConstraints];
    }

Appleのドキュメントがsuperを最後のステップとして呼び出すことを推奨していることを指摘したコメントで@fresidueに乾杯。いくつかの制約を変更する前にsuperを呼び出すと、ランタイム例外が発生する可能性があります(クラッシュ)。

33
BooRanger

これは、AppleおよびドキュメントからのWWDCビデオに従って、ViewDidLoadで行う必要があります。

人々がupdateConstraintsを推奨する理由はわかりません。 updateConstraintsで行うと、ビューで既に自動マスクが考慮されているため、自動サイズ変更でNSAutoresizingMaskLayoutConstraintの問題が発生します。 updateConstraintsでそれらを削除して機能させる必要があります。

UpdateConstraintsは、それらを「更新」する必要がある場合にのみ使用する必要があり、初期設定から変更などを行います。

4
BluelineCoding

これらはviewWillLayoutSubviews:でも設定できます:

 override func viewWillLayoutSubviews() {

    if(!wasViewLoaded){
        wasViewLoaded = true

        //update constraint

        //also maybe add a subview            
    }
}
1
Andre Simon

ストーリーボードにいる人がロードされる前に制約を変更するこのソリューションがあります。このソリューションは、ビューがロードされた後の遅延を取り除きます。

-(void)updateViewConstraints{

    dispatch_async(dispatch_get_main_queue(), ^{

            //Modify here your Constraint -> Activate the new constraint and deactivate the old one

            self.yourContraintA.active = true;
            self.yourContraintB.active= false;
            //ecc..
           });

    [super updateViewConstraints]; // This must be the last thing that you do here -> if! ->Crash!
}
1
Davide

レイアウトサブビューメソッドをビューで実行します

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
}
1
Kit

これは私のために働いた:

Swift 4.2

override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

// Modify your constraints in here

  ...

}

正直なところ、それが価値があるかどうかはわかりません。 viewDidLoad()よりもロードが少し遅いようです。巨大になっているので、後者から移動したかっただけです。

0