iphone - 호출 - swift4 layoutsubviews




UIView의 setNeedsLayout, layoutIfNeeded 및 layoutSubviews 사이의 관계는 무엇입니까? (2)

나는 아직도 자신을 알아 내려고 노력하고 있습니다. 그래서 약간의 회의론으로 이것을 받아 들여서 오류가 있다면 저를 용서해주십시오.

setNeedsLayout 은 쉬운 것입니다 : UIView의 어딘가에 레이아웃을 필요로하는 플래그를 설정합니다. 그러면 다음 재 렌더링이 발생하기 전에 layoutSubviews 가 뷰에서 호출됩니다. 많은 경우 autoresizesSubviews 속성 때문에 명시 적으로이 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 를 호출하여 뷰를 강제로 배치하고 필요할 때 수퍼 뷰를 즉시 배치 할 수 있습니다.

누구든지 UIView's setNeedsLayout , layoutIfNeededlayoutSubviews 메서드 간의 관계에 대한 확실한 설명을 줄 수 있습니까? 그리고 세 가지 모두 사용되는 예제 구현. 감사.

내가 혼란스러워하는 이유는, 커스텀 뷰를 보내면이 메소드 다음에 호출되는 바로 다음 setNeedsLayout 메시지가 layoutSubviews 이고 layoutIfNeeded 바로 건너 layoutIfNeeded . 문서에서 나는 흐름이 setNeedsLayout > layoutIfNeeded 가 호출되도록합니다.> layoutSubviews 가 호출되도록합니다.


어떤 경우에는 setNeedsLayout 을 호출하고 layoutIfNeeded 를 호출해야하는 n8gray의 대답을 추가하고 layoutIfNeeded .

예를 들어 하위 뷰의 위치가 복잡하고 autoresizingMask 또는 iOS6 AutoLayout을 사용하여 수행 할 수없는 UIView를 확장하는 사용자 정의보기를 작성했다고 가정 해 보겠습니다. 맞춤 위치 지정은 layoutSubviews 를 재정 의하여 수행 할 수 있습니다.

예를 들어, contentView 속성과 contentView 주위의 여백을 설정할 수있는 edgeInsets 속성이있는 사용자 정의보기가 있다고 가정 해 보겠습니다. 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 속성을 변경할 때마다 프레임 변경을 애니메이션으로 만들려면 다음과 같이 edgeInsets 설정 edgeInsets 재정의하고 setNeedsLayout 다음에 layoutIfNeeded 호출 setNeedsLayout .

- (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 플래그가 설정되지 않으므로 아무 것도 발생하지 않습니다.





uiview