UIView의 setNeedsLayout, layoutIfNeeded 및 layoutSubviews 간의 관계는 무엇입니까?
누구든지 UIView's
setNeedsLayout
, layoutIfNeeded
및 layoutSubviews
메서드 간의 관계에 대한 명확한 설명을 할 수 있습니까 ? 그리고 세 가지가 모두 사용되는 예제 구현입니다. 감사.
나를 혼란스럽게하는 것은 내가 내 사용자 정의보기에 setNeedsLayout
메시지를 보내면 이 메서드 이후에 호출되는 바로 다음 작업은 layoutSubviews
바로 건너 뛰는 것 layoutIfNeeded
입니다. 문서에서 나는 흐름이 setNeedsLayout
> layoutIfNeeded
호출되는 원인> 호출되는 원인 이 될 것으로 예상합니다 layoutSubviews
.
나는 여전히 이것을 스스로 알아 내려고 노력하고 있으므로 약간의 회의적으로 이것을 받아들이고 오류가 있으면 나를 용서하십시오.
setNeedsLayout
쉬운 것입니다. UIView 어딘가에 레이아웃이 필요한 것으로 표시하는 플래그를 설정합니다. layoutSubviews
다음 다시 그리기가 발생하기 전에 뷰에서 강제 로 호출됩니다. 대부분의 경우 autoresizesSubviews
속성 때문에 이것을 명시 적으로 호출 할 필요가 없습니다 . 이것이 설정되면 (기본적으로) 뷰의 프레임을 변경하면 뷰가 하위 뷰를 레이아웃하게됩니다.
layoutSubviews
모든 흥미로운 작업을 수행하는 방법입니다. drawRect
원한다면 레이아웃 과 동일 합니다. 간단한 예는 다음과 같습니다.
-(void)layoutSubviews {
// Child's frame is always equal to our bounds inset by 8px
self.subview1.frame = CGRectInset(self.bounds, 8.0, 8.0);
// It seems likely that this is incorrect:
// [self.subview1 layoutSubviews];
// ... and this is correct:
[self.subview1 setNeedsLayout];
// but I don't claim to know definitively.
}
AFAIK layoutIfNeeded
는 일반적으로 하위 클래스에서 재정의되는 것을 의미하지 않습니다. 지금 당장 뷰를 배치하고 싶을 때 호출해야하는 메서드입니다 . Apple의 구현은 다음과 같습니다.
-(void)layoutIfNeeded {
if (self._needsLayout) {
UIView *sv = self.superview;
if (sv._needsLayout) {
[sv layoutIfNeeded];
} else {
[self layoutSubviews];
}
}
}
layoutIfNeeded
뷰를 요청 하여 뷰 (및 필요에 따라 수퍼 뷰)가 즉시 배치되도록합니다.
나는 어떤 경우에는 당신이 호출해야한다는 n8gray의 대답에 추가 할 setNeedsLayout
다음에 layoutIfNeeded
.
예를 들어 하위 뷰의 위치가 복잡하고 autoresizingMask 또는 iOS6 AutoLayout으로 수행 할 수없는 UIView를 확장하는 사용자 정의 뷰를 작성했다고 가정 해 보겠습니다. 사용자 지정 위치 지정은을 재정 의하여 수행 할 수 있습니다 layoutSubviews
.
예를 들어 contentView
속성 이있는 사용자 지정보기 와 edgeInsets
contentView 주변에 여백을 설정할 수 있는 속성이 있다고 가정 해 보겠습니다 . layoutSubviews
다음과 같이 보일 것입니다.
- (void) layoutSubviews {
self.contentView.frame = CGRectMake(
self.bounds.origin.x + self.edgeInsets.left,
self.bounds.origin.y + self.edgeInsets.top,
self.bounds.size.width - self.edgeInsets.left - self.edgeInsets.right,
self.bounds.size.height - self.edgeInsets.top - self.edgeInsets.bottom);
}
당신이 변경할 때마다 프레임 변화를 애니메이션 할 수있게하려면 edgeInsets
속성을, 당신은 오버라이드 (override) 할 필요가 edgeInsets
다음과 호출로 세터를 setNeedsLayout
다음 layoutIfNeeded
:
- (void) setEdgeInsets:(UIEdgeInsets)edgeInsets {
_edgeInsets = edgeInsets;
[self setNeedsLayout]; //Indicates that the view needs to be laid out
//at next update or at next call of layoutIfNeeded,
//whichever comes first
[self layoutIfNeeded]; //Calls layoutSubviews if flag is set
}
이렇게하면 다음을 수행하면 애니메이션 블록 내에서 edgeInsets 속성을 변경하면 contentView의 프레임 변경이 애니메이션으로 표시됩니다.
[UIView animateWithDuration:2 animations:^{
customView.edgeInsets = UIEdgeInsetsMake(45, 17, 18, 34);
}];
setEdgeInsets 메서드에서 layoutIfNeeded에 대한 호출을 추가하지 않으면 다음 업데이트주기에서 layoutSubviews가 호출되므로 애니메이션 블록 외부에서 호출하는 것과 동일하므로 애니메이션이 작동하지 않습니다.
setEdgeInsets 메서드에서 layoutIfNeeded 만 호출하면 setNeedsLayout 플래그가 설정되지 않았으므로 아무 일도 발생하지 않습니다.
'IT story' 카테고리의 다른 글
여러 도메인에 대한 단일 사인온 [닫힘] (0) | 2020.08.12 |
---|---|
버전 번호 자동 업데이트 (0) | 2020.08.12 |
하드웨어없이 CUDA 프로그래밍을위한 GPU 에뮬레이터 (0) | 2020.08.12 |
십자 축을 채우기 위해 아이들을 늘리는 방법? (0) | 2020.08.12 |
dSYM은 무엇이며 어떻게 사용합니까? (0) | 2020.08.12 |