web-dev-qa-db-ja.com

ビューのフレームをviewDidLoadで手動で設定する必要があるのはなぜですか?

UITabBarController内にUINavigationControllerを使用した非常に基本的なセットアップがあります。そのnavcontrollerのrootViewControllerのビューをプログラムでレイアウトしたいのですが、viewDidLoad内のself.view.frameを見ると、次のようになります(たとえば、landscape):

1. view frame: {{20, 0}, {748, 1024}} // looks like an odd portrait mode

次に、ポートレートに自動回転し、これを取得します。

2. view frame: {{0, 0}, {768, 911}}

次に、Landscapeに戻ると、フレームは次のようになっています。

3. view frame: {{0, 0}, {1024, 655}}

さらに自動回転イベントがフレーム値#2と#3の間でフリップフロップします。

#1の奇妙さを回避するために、私は現在viewDidLoadでこれを行っています:

if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
    self.view.frame = CGRectMake(0, 0, 768, 911);
} else {
    self.view.frame = CGRectMake(0, 0, 1024, 655);
}

ここに何かが欠けているようです。ビューのデフォルトのフレームが自動回転して同じ方向に戻るときに、フレームと一致しないのはなぜですか?ビューフレームが初期方向に設定されていませんか?非常に混乱...

私の厄介なハックを含め、上記のどれも視覚的に何も変更しないことを言及する必要があります。私がハックを行った理由は、サブビューをこのビューにレイアウトするときに、ナビゲーションバーのすぐ左上にある、予想される場所に基づいてサブビューが配置されるようにするためです。

何が悪いのですか?

更新:ビューのすべての自動サイズ設定をオフにすると、結果#1が次のように変更されます。

view frame: {{0, 0}, {748, 1024}}

それは少し近いように見えますが、それでも#3とは一致しません。

32
Ryan Waggoner

ビューが最終的に表示されるときと同じように、viewDidLoadでフレームが同じであるとは限りません。 UIKitは、表示されるコンテキストに基づいて、表示する前にViewControllerのビューのフレームを調整します。サイズは、インターフェイスの向きと、表示されているナビゲーションバー、タブバー、ツールバー、またはステータスバー(電話中などに変更できる高さ)の寸法に基づいて決定されます。

ビューコントローラのビューがロードおよび表示されたときに何が起こるかを理解するのに役立ちます。

  1. 何かが初めてビューコントローラーのviewプロパティにアクセスします。これは、独自のコードで、またはタブの選択などのユーザーアクションに応答してUIKitで発生する可能性があります。

  2. UIKitは、ビューコントローラーのビューが定義されている場合はloadViewを呼び出すか、initWithNibName:bundle:で指定されたNIBからビューをロードすることで遅延ロードします。どちらも存在しない場合、UIKitは空のビューをロードするだけです。

  3. ビューとそのサブビューが完全に読み込まれると、UIKitはviewDidLoadを呼び出します。 この時点で、ビューのフレームは、NIBまたはloadViewで設定されたものになります。 ==

  4. 何かがUIKitにビューコントローラーのビューを表示するように要求します。繰り返しになりますが、これはタブをタップするなどのユーザーアクション、またはpushViewController:animated:presentModalViewController:animated:などのコード内の明示的なメソッド呼び出しの可能性があります。

  5. UIKitは、上記のように、表示されるコンテキストに基づいてビューのサイズを変更します。

  6. UIKitはviewWillAppear:を呼び出します。 これで、フレームは表示されるサイズになります。(?)編集:これはもはや真実ではないかもしれません。以下のコメントを参照してください。

  7. UIKitは、アニメーション付きまたはアニメーションなしでビューを表示します。

  8. UIKitはviewDidAppear:を呼び出します。

ご覧のとおり、表示される前にビューのフレームのサイズを知る必要がある場合は、viewWillAppear:が唯一の機会です。このサイズは、回転イベントやステータスバーの高さの変更など、さまざまな理由でビューが表示された後に変更される可能性があることに注意してください。このため、すべてのサブビューに適切なautoresizingMaskを設定し、レイアウトが境界の変更に合わせて適切に調整されるようにすることが重要です。

ビュー階層を手動で構築したい場合、そのために推奨される場所はloadViewです。このメソッドでビューを自分で作成するので、フレームを好きなように初期化できます。 UIKitはとにかくそれを変更する可能性があるため、選択するサイズはそれほど重要ではありません。 autoresizingMasksを適切に設定していることを確認してください。

98
cduhn