LayoutSubviews,layoutIfNeeded,setNeedsLayoutトリガタイミングとルール
7376 ワード
作者:伝説のサイダー銃の住所:https://www.jianshu.com/p/f17ac629dbc0著作権はすべて、転載を歓迎して、転載して出典を明記して、伝言の評論を歓迎します.
実際の開発過程や面接では、このような問題に直面することがあります.まず、関連するテストコードを使用します.
出力:
出力:
結論1
上記の2つの例は、 viewの初期化frameかどうかにかかわらずlayoutSubview はトリガーされません.他のviewに追加された場合にのみlayoutSubviewがトリガーされ、次のviewリフレッシュ時にlayoutSubview がトリガーされます.
出力:
注意:ここでのchangeFrameには、x,y,width,heightのいずれかの値が含まれます.
結論2:
フレームを変更するとlayoutSubviewsがトリガーされます(変更時にトリガーされるのではなく、次のリフレッシュサイクルでトリガーされます)
出力:
結論3
layoutIfNeeded frameが変化していない場合、何の効果もありません.
出力:
結論4
frame変化とlayoutIfNeededはすぐにlayoutSubviewsをトリガーします
出力:
結論5
frameは変わりません.setNeedsLayoutはlayoutSubviewsを強制しますが、次のページのリフレッシュサイクルです.
しゅつりょく
次のテストの結果と同じです
setNeedsLayoutが呼び出されると、frameが変化するかどうかにかかわらず、次のインタフェースリフレッシュサイクルでlayoutSubviews が呼び出されます. layoutIfNeededが呼び出され、frameが変化するとlayoutSubviewsが呼び出されます.そうしないとlayoutSubviews は呼び出されません. layoutSubviewsトリガのタイミング 他のビューに自分を追加する場合、サブビューを追加するときはトリガーされず、次のリフレッシュサイクルのときに が呼び出される. Frameが変化するとき、そして次のリフレッシュサイクルのときに が呼び出される setNeedsLayoutは、次のリフレッシュサイクル時に を呼び出す Frameが変化するlayoutIfNeededが呼び出されると、すぐに呼び出され、現在のサイクルで が呼び出されます.
実際の開発過程や面接では、このような問題に直面することがあります.まず、関連するテストコードを使用します.
View RXLayoutViewのテスト
@implementation RXLayoutView
- (id)init
{
if (self = [super init]) {
self.backgroundColor = [UIColor redColor];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor redColor];
}
return self;
}
- (void)layoutSubviews
{
printf("RXLayoutView layoutSubviews
");
}
@end
frameはzero
- (void)_test_layoutSubviews_zeroFrame
{
RXLayoutView *view = [[RXLayoutView alloc] init];
printf("after alloc init
");
[self.view addSubview:view];
printf("after add
");
}
出力:
after alloc initWithFrame
after add
RXLayoutView layoutSubviews
frameはNoneZero
- (void)_test_layoutSubviews_noneZeroFrame
{
RXLayoutView *view = [[RXLayoutView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
printf("after alloc initWithFrame
");
[self.view addSubview:view];
printf("after add
");
}
出力:
after alloc initWithFrame
after add
RXLayoutView layoutSubviews
結論1
上記の2つの例は、
addSubview
を削除した場合、3行目の結果は出力されません.上記の2つの例から出力順序と結果に気づき,我々はlayoutSubviews_noneZeroFrame_changeFrame
- (void)_test_layoutSubviews_noneZeroFrame_changeFrame
{
RXLayoutView *view = [[RXLayoutView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
printf("after alloc initWithFrame
");
[self.view addSubview:view];
printf("after add
");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
printf("before change frame
");
view.frame = CGRectMake(100, 200, 200, 200);
printf("after change frame
");
});
});
}
出力:
after alloc initWithFrame
after add
RXLayoutView layoutSubviews
before change frame
after change frame
RXLayoutView layoutSubviews
注意:ここでのchangeFrameには、x,y,width,heightのいずれかの値が含まれます.
結論2:
フレームを変更するとlayoutSubviewsがトリガーされます(変更時にトリガーされるのではなく、次のリフレッシュサイクルでトリガーされます)
layoutSubviews_noneZeroFrame_layoutIfNeeded
- (void)_test_layoutSubviews_noneZeroFrame_layoutIfNeeded
{
RXLayoutView *view = [[RXLayoutView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
printf("after alloc initWithFrame
");
[self.view addSubview:view];
printf("after add
");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
printf("before layoutIfNeeded
");
[view layoutIfNeeded];
printf("after layoutIfNeeded
");
});
});
}
出力:
after alloc initWithFrame
after add
RXLayoutView layoutSubviews
before layoutIfNeeded
after layoutIfNeeded
結論3
layoutIfNeeded frameが変化していない場合、何の効果もありません.
layoutSubviews_noneZeroFrame_changeFrame_layoutIfNeeded
- (void)_test_layoutSubviews_noneZeroFrame_changeFrame_layoutIfNeeded
{
RXLayoutView *view = [[RXLayoutView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
printf("after alloc initWithFrame
");
[self.view addSubview:view];
printf("after add
");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
printf("before change frame and layoutIfNeeded
");
view.frame = CGRectMake(100, 200, 200, 200);
[view layoutIfNeeded];
printf("after change frame and layoutIfNeeded
");
});
});
}
出力:
after alloc initWithFrame
after add
RXLayoutView layoutSubviews
before change frame and layoutIfNeeded
RXLayoutView layoutSubviews
after change frame and layoutIfNeeded
結論4
frame変化とlayoutIfNeededはすぐにlayoutSubviewsをトリガーします
layoutSubviews_noneZeroFrame_setNeedsLayout
- (void)_test_layoutSubviews_noneZeroFrame_setNeedsLayout
{
RXLayoutView *view = [[RXLayoutView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
printf("after alloc initWithFrame
");
[self.view addSubview:view];
printf("after add
");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
printf("before setNeedsLayout
");
[view setNeedsLayout];
printf("after setNeedsLayout
");
});
});
}
出力:
after alloc initWithFrame
after add
RXLayoutView layoutSubviews
before setNeedsLayout
after setNeedsLayout
RXLayoutView layoutSubviews
結論5
frameは変わりません.setNeedsLayoutはlayoutSubviewsを強制しますが、次のページのリフレッシュサイクルです.
layoutSubviews_noneZeroFrame_changeFrame_setNeedsLayout
- (void)_test_layoutSubviews_noneZeroFrame_changeFrame_setNeedsLayout
{
RXLayoutView *view = [[RXLayoutView alloc] initWithFrame:CGRectMake(100, 200, 100, 100)];
printf("after alloc initWithFrame
");
[self.view addSubview:view];
printf("after add
");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
printf("before change frame and setNeedsLayout
");
view.frame = CGRectMake(100, 200, 200, 200);
printf("after change frame and before setNeedsLayout
");
[view setNeedsLayout];
printf("after change frame and setNeedsLayout
");
});
});
}
しゅつりょく
after alloc initWithFrame
after add
RXLayoutView layoutSubviews
before change frame and setNeedsLayout
after change frame and before setNeedsLayout
after change frame and setNeedsLayout
RXLayoutView layoutSubviews
次のテストの結果と同じです