web-dev-qa-db-ja.com

viewWillAppear:とviewDidAppearの間のビューフレームの変更:

アプリケーションで奇妙な動作を発見しました。接続されたIBOutletが、View ControllerのviewWillAppear:およびviewDidAppear:UIViewControllerサブクラスに関連するコードは次のとおりです。

-(void)viewWillAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

-(void)viewDidAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

結果のログ出力:

MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 0; 0 0); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 44; 320 416); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>

これは、フレームが2つの呼び出し間で変化していることを明確に示しています。 viewDidLoadメソッドのビューを使用してセットアップを行いたかったのですが、コンテンツが画面上に表示されるまで変更できない場合、それはほとんど役に立たないようです。何が起きているのでしょうか?

83
Jumhyn

Autolayoutは、ビューのGUIを設計および開発する方法に大きな変更を加えました。主な違いの1つは、autolayoutはビューサイズをすぐに変更せず、トリガーされたときのみ、つまり特定の時間に変更することですが、制約をすぐに再計算するか、「レイアウトが必要です。 _-setNeedDisplay_のように機能します。
私にとっての大きな課題は、自動サイズ変更マスクを使用する必要がなくなり、ビューを配置する際にフレームが役に立たなくなったことを理解して受け入れることでした。ビューの位置についてはもう考える必要はありませんが、お互いに関連する空間でどのように見たいかを考える必要があります。
古い自動サイズ変更マスクと自動レイアウトを混在させたい場合は、問題が発生します。すぐに自動レイアウトの実装について考え、自動レイアウトに基づいてビュー階層に古いアプローチを混在させないようにする必要があります。
View Controllerのメインビューなど、自動サイズ変更マスクのみを使用するコンテナビューを作成しても構いませんが、混在させない方が良いでしょう。
ストーリーボードを使用したことはありませんが、ほとんどの場合正しいです。自動レイアウトを使用すると、自動レイアウトエンジンが計算を開始するときにビューのフレームが設定されます。 View Controllerの- (void)viewDidLayoutSubviewsメソッドのスーパーの直後に同じことを尋ねてみてください。
このメソッドは、自動レイアウトエンジンがビューのフレームの計算を終了したときに呼び出されます。

107
Andrea

ドキュメント: から

viewWillAppear:

ビューがビュー階層に追加されようとしていることをView Controllerに通知します。

viewDidAppear:

ビューがビュー階層に追加されたことをView Controllerに通知します。

その結果、サブビューのフレームはviewWillAppearにまだ設定されていません。

ビューが画面に表示される前にUIを変更する適切な方法は次のとおりです。

viewDidLayoutSubviews

View Controllerに、ビューがサブビューをレイアウトしたことを通知します。

153

コール

self.scrollView.layoutIfNeeded()

viewWillAppearメソッドで。その後、そのフレームにアクセスでき、viewDidAppearで印刷するのと同じ値になります。

7
andrei

私の場合、すべてのフレーム関連のメソッドを

override func viewWillLayoutSubviews()

完全に機能しました(ストーリーボードから制約を変更しようとしていました)。