layoutSubviews, layoutIfNeeded, setNeedsLayout 트리거 시기와 규칙
실제 개발 과정이나 면접에서 이런 문제가 발생할 수 있으니 관련 테스트 코드를 먼저 사용하세요.
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
상술한 두 가지 예는
addSubview
를 없앨 때 세 번째 줄의 결과를 출력하지 않는다.상술한 두 가지 예에서 출력 순서와 결과를 알아차리면 우리는 알 수 있다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 프레임이 변하지 않았을 때 아무런 효과가 없습니다.
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
결론
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
저번 테스트 결과랑 똑같아요.
요약:
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.