アニメーション中にlayoutSubview
メッセージを受け取らないカスタムビューがあります。
私は、画面全体に広がるビューを持っています。ナビゲーションバーの高さを変更すると、Interface Builderで正しくサイズ変更されるカスタムサブビューが画面の下部にあります。 layoutSubviews
は、ビューが作成されるときに呼び出されますが、二度と呼び出されることはありません。私のサブビューは正しくレイアウトされています。呼び出し中のステータスバーをオフに切り替えると、メインビューがサイズ変更をアニメーション化しても、サブビューのlayoutSubviews
はまったく呼び出されません。
layoutSubviews
はどのような状況で実際に呼び出されますか?
カスタムビューのautoresizesSubviews
をNO
に設定しています。 Interface Builderには、上下の支柱と垂直矢印が設定されています。
パズルのもう1つの部分は、ウィンドウをキーにする必要があることです。
[window makeKeyAndVisible];
その他のサブビューは自動的にサイズ変更されません。
シミュレートされた画面要素がオンになっているビュー(ステータスバーなど)でスプリングを変更できないというInterface Builderの主張に至るまで、ソリューションを追跡しました。メインビューではスプリングがオフになっているため、そのビューのサイズを変更することはできず、コールバーが表示されたときに全体が下にスクロールされました。
シミュレートされた機能をオフにしてから、ビューのサイズを変更し、スプリングを正しく設定すると、アニメーションが発生し、メソッドが呼び出されました。
これをデバッグする際の追加の問題は、メニューで通話中のステータスが切り替えられたときにシミュレータがアプリを終了することです。アプリを終了=デバッガーなし。
私は同様の質問をしましたが、答え(またはネットで見つけることができるもの)に満足していなかったので、実際に試しましたが、ここに私が得たものがあります:
init
はlayoutSubviews
を呼び出しません(duh)addSubview:
により、追加されるビュー、追加されるビュー(ターゲットビュー)、およびターゲットのすべてのサブビューでlayoutSubviews
が呼び出されます。setFrame
は、フレームのサイズパラメータが異なる場合にのみ、フレームが設定されたビューでlayoutSubviews
をインテリジェントに呼び出します。layoutSubviews
がscrollViewとそのスーパービューで呼び出されますlayoutSubview
のみが呼び出されますlayoutSubviews
が呼び出されます私の結果- http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/
@BadPirateによる以前の回答に基づいて、私はもう少し実験して、いくつかの明確化/修正を思いつきました。次の場合に限り、ビューでlayoutSubviews:
が呼び出されることがわかりました。
関連する詳細:
layoutSubviews:
が呼び出されるのはそのためです。layoutSubviews:
を呼び出します。setNeedsLayout
を呼び出します。実行ループの各反復、ビュー階層内のすべてのビューについて、このフラグがチェックされます。フラグが立てられていることが確認された各ビューについて、layoutSubviews:
が呼び出され、フラグがリセットされます。階層の上位のビューが最初にチェック/呼び出されます。ビューで次のイベントのいずれかが発生すると、レイアウトの変更が発生する可能性があります。
a。ビューの境界長方形のサイズが変わります。
b。インターフェースの向きの変更が発生し、通常、ルートビューの境界の長方形が変更されます。
c。ビューのレイヤーに関連付けられているCore Animationサブレイヤーのセットが変更され、レイアウトが必要になります。
d。ビューのsetNeedsLayout
または_layoutIfNeeded
メソッドを呼び出すことにより、アプリケーションはレイアウトを強制的に実行します。
e。アプリケーションは、ビューの基になるレイヤーオブジェクトのsetNeedsLayout
メソッドを呼び出してレイアウトを強制します。
BadPirate's answer のポイントの一部は、部分的にのみ真です:
addSubView
ポイントの場合
addSubview
を使用すると、追加されるビュー、追加されるビュー(ターゲットビュー)、およびターゲットのすべてのサブビューでlayoutSubviewsが呼び出されます。
ビューの(ターゲットビュー)自動サイズ変更マスクに依存します。自動サイズ変更マスクがオンの場合、addSubview
ごとにlayoutSubviewが呼び出されます。自動サイズ変更マスクがない場合、layoutSubviewは、ビューの(ターゲットビュー)フレームサイズが変更されたときにのみ呼び出されます。
例:UIViewをプログラムで作成した場合(デフォルトでは自動サイズ変更マスクはありません)、LayoutSubviewはUIViewフレームがすべてのaddSubview
で変更されない場合にのみ呼び出されます。
この手法により、アプリケーションのパフォーマンスも向上します。
デバイスの回転点
デバイスを回転すると、親ビュー(応答するviewControllerのプライマリビュー)でlayoutSubviewのみが呼び出されます
これは、VCがVC階層(window.rootViewController
のルート)にある場合にのみ当てはまります。これは最も一般的なケースです。 iOS 5では、VCを作成しても別のVCに追加されていない場合、デバイスの回転時にこのVCが認識されません。したがって、そのビューは、layoutSubviewsを呼び出しても認識されません。
viewControllerで[self.view setNeedsLayout];
を呼び出すと、viewDidLayoutSubviewsが呼び出されます
あなたはlayoutIfNeededを見ましたか?
ドキュメントスニペットは以下のとおりです。アニメーション中にこのメソッドを明示的に呼び出すと、アニメーションは機能しますか?
layoutIfNeeded必要に応じてサブビューをレイアウトします。
- (void)layoutIfNeeded
ディスカッションこのメソッドを使用して、描画前にサブビューのレイアウトを強制します。
可用性iPhone OS 2.0以降で使用できます。
OpenGLアプリをSDK 3から4に移行するときに、layoutSubviewsが呼び出されなくなりました。たくさんの試行錯誤の後、ようやくMainWindow.xibを開き、ウィンドウオブジェクトを選択し、インスペクターで[ウィンドウ属性]タブ(左端)を選択し、[起動時に表示]をオンにしました。 SDK 3では、layoutSubViews呼び出しを行うために使用されていたようですが、4ではそうではありません。
6時間のフラストレーションが終わりました。
パズルのもう1つの部分は、ウィンドウをキーにする必要があることです。
[window makeKeyAndVisible];
その他のサブビューは自動的にサイズ変更されません。
layoutSubviews
が呼び出されない場合の、あいまいでありながら潜在的に重要なケースは次のとおりです。
import UIKit
class View: UIView {
override class var layerClass: AnyClass { return Layer.self }
class Layer: CALayer {
override func layoutSublayers() {
// if we don't call super.layoutSublayers()...
print(type(of: self), #function)
}
}
override func layoutSubviews() {
// ... this method never gets called by the OS!
print(type(of: self), #function)
}
}
let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))