setNeedsLayout vs. setNeedsUpdateConstraints 및 layoutIfNeeded vs updateConstraintsIfNeeded


227

자동 레이아웃 체인은 기본적으로 3 가지 프로세스로 구성됩니다.

  1. 구속 조건 업데이트
  2. 레이아웃 뷰 (여기서 프레임 계산을 수행하는 위치)
  3. 디스플레이

무엇 완전히 나에게 분명하지 않다 것은 사이의 내부 차이 -setNeedsLayout-setNeedsUpdateConstraints. Apple Docs에서 :

setNeedsLayout

뷰의 서브 뷰 레이아웃을 조정하려면 응용 프로그램의 메인 스레드에서이 메소드를 호출하십시오. 이 메소드는 요청을 기록하고 즉시 리턴합니다. 이 방법은 즉시 업데이트를 강제하지 않지만 대신 다음 업데이트주기를 기다리기 때문에 여러 뷰의 레이아웃을 무효화하여 해당 뷰를 업데이트 할 수 있습니다. 이 동작을 통해 모든 레이아웃 업데이트를 한 번의 업데이트 주기로 통합 할 수 있으며 이는 일반적으로 성능이 향상됩니다.

setNeedsUpdateConstraints

사용자 지정 뷰의 속성이 제약 조건에 영향을주는 방식으로 변경되면이 메서드를 호출하여 나중에 제약 조건을 업데이트해야 함을 나타낼 수 있습니다. 그런 다음 시스템은 일반 레이아웃 패스의 일부로 updateConstraints를 호출합니다. 구속 조건을 요구하기 바로 전에 한 번에 모두 구속 조건을 업데이트하면 배치 단계 사이에서 뷰를 여러 번 변경할 때 구속 조건을 불필요하게 다시 계산할 필요가 없습니다.

제약 조건을 수정 한 후 뷰에 애니메이션을 적용하고 변경 사항에 애니메이션을 적용하려면 일반적으로 예를 들어 호출합니다.

[UIView animateWithDuration:1.0f delay:0.0f usingSpringWithDamping:0.5f initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.modifConstrView setNeedsUpdateConstraints];
        [self.modifConstrView layoutIfNeeded];
    } completion:NULL];

내가 사용하는 경우 사실을 발견했습니다 -setNeedsLayout대신 -setNeedsUpdateConstraints모든 작업이 예상대로,하지만 난 변경하는 경우 -layoutIfNeeded-updateConstraintsIfNeeded, 애니메이션은 일어나지 않을 것입니다.
나는 내 자신의 결론을 만들려고 노력했다.

  • -updateConstraintsIfNeeded 구속 조건 만 업데이트하지만 레이아웃을 강제로 프로세스로 가져 오지 않으므로 원본 프레임이 계속 유지됩니다.
  • -setNeedsLayout-updateContraints메소드 도 호출

그렇다면 언제 다른 것을 사용하는 것이 좋을까요? 레이아웃 방법에 대해 제약 조건이나 상위 뷰가 변경된 뷰에서 호출해야합니까?


27
사람들이 downvoting을 이해하지 못합니다 ... 정말로. 따라서 당신은 의무적 인 이유를 묻는 것과 같이 또는 그것에 대해 전혀 무의미한 것과 같이 그것에 대해 무언가를해야합니다
Andrea

7
아마도 그들은 단지 비평가 배지 (첫 번째 투표)를 얻어야합니다
fujianjin6471

1
나는 당신이 여기 를 볼 것을 적극 권장합니다 . 대답은 실제 문제에 대한 해결책입니다. 이 비디오
Honey

답변:


258

당신의 결론은 옳습니다. 기본 체계는 다음과 같습니다.

  • setNeedsUpdateConstraints앞으로 전화를해야 updateConstraintsIfNeeded합니다 updateConstraints.
  • setNeedsLayout앞으로 전화를해야 layoutIfNeeded합니다 layoutSubviews.

경우 layoutSubviews라고, 또한 호출 updateConstraintsIfNeeded때문에 수동으로 거의 내 경험에 필요하지 않습니다 호출. 실제로 레이아웃을 디버깅 할 때를 제외하고는 호출하지 않았습니다.

자동 제약 조건을 사용하여 제약 조건을 업데이트하는 setNeedsUpdateConstraints것도 매우 드,니다. objc.io는 자동 레이아웃에 대해 읽어야합니다 .

나중에 변경되어 제약 조건 중 하나가 무효화되는 경우 제약 조건을 즉시 제거하고 setNeedsUpdateConstraints를 호출해야합니다. 실제로, 제약 조건 업데이트 패스를 트리거해야하는 유일한 경우입니다.

또한 내 경험상 제약 조건을 무효화 할 필요가 없었으며 setNeedsLayout코드의 다음 줄에서 설정하지 않아도 되었습니다. 새로운 제약 조건이 거의 새로운 레이아웃을 요구하기 때문입니다.

경험 법칙은 다음과 같습니다.

  • 제약 조건을 직접 조작 한 경우을 호출하십시오 setNeedsLayout.
  • 당신은 (오프셋 또는 떨어지게 같은) 일부 조건 변경 한 경우 재정의 된 제약 조건 변경 updateConstraints(BTW, 변경 제약에 권장되는 방법) 메소드를 호출 setNeedsUpdateConstraints하고, 대부분의 시간, setNeedsLayout그 이후를.
  • 예를 들어 레이아웃 패스 후 새로운 프레임 높이를 배워야 할 때와 같이 즉각적인 효과를 얻기 위해 위의 작업이 필요한 경우을 추가하십시오 layoutIfNeeded.

또한 애니메이션 코드 setNeedsUpdateConstraints에서 애니메이션 전에 수동으로 구속 조건이 업데이트되고 애니메이션이 이전과 새로운 차이점의 차이에 따라 뷰를 다시 레이아웃하기 때문에 필요하지 않다고 생각 합니다.


@coverback, 그래서 objc.io는 "나중에 변경 사항 중 하나가 제약 조건 중 하나를 무효화하는 경우 제약 조건을 즉시 제거하고 setNeedsUpdateConstraints를 호출해야합니다. 실제로 제약 조건 업데이트 패스를 트리거해야하는 유일한 경우입니다."라고 말합니다. 그런 다음 애니메이션 블록에서 constraint.contant를 제거, 추가 또는 변경할 때 setNeedsLayout을 호출해야한다고 말합니다. 차이점이 뭐야? 나는 정말 바보 같은 느낌 :(
pash3r

3
@ pash3r 차이점 업데이트 상수가 "유효하지 않음"으로 규정되지 않습니다. 무효화는 더 이상 관련이없는 경우입니다. 다른 뷰에 연결하거나 완전히 제거해야합니다. 상수는 뷰를 더 가까이 또는 더 멀리 배치하거나 크기를 변경하여에 대한 필요성을 나타 setNeedsLayout냅니다.
커버 백

@coverback setNeedsLayoutlayoutSubviews다음 업데이트주기에서 호출 될 것이지만 아마도 이것은 아무 관련이 layoutIfNeeded없습니까?
fujianjin6471

2
@coverback 제약 조건을 직접 조작하면 layoutSubviews자동으로 호출됩니다. 전화 할 필요가 없습니다setNeedsLayout
fujianjin6471

예, 제약 조건의 속성을 직접 조작하면이 트리거 layoutSubviews되므로 수동으로 할 필요가 없습니다. 당신은, 그러나, 전화를해야합니까 layoutIfNeeded당신이 변경 사항을 적용하려면 아니라, 즉시 다음의 레이아웃주기가 필요한 경우
찰리 마틴

89

coverback에 의한 대답은 꽤 정확합니다. 그러나 추가 세부 정보를 추가하고 싶습니다.

다음은 다른 동작을 설명하는 일반적인 UIView주기 다이어그램입니다.

UIView의 라이프 사이클

  1. 내가 사용하는 경우 사실을 발견했습니다 -setNeedsLayout대신 -setNeedsUpdateConstraints모든 작업이 예상대로,하지만 난 변경하는 경우 -layoutIfNeeded-updateConstraintsIfNeeded, 애니메이션은 일어나지 않을 것입니다.

updateConstraints일반적으로 아무것도하지 않습니다. layoutSubviews호출 될 때까지 적용되지 않는 제약 조건을 해결합니다 . 따라서 애니메이션에는에 대한 호출이 필요합니다 layoutSubviews.

  1. setNeedsLayout도 -updateContraints 메소드를 호출합니다.

필요하지 않습니다. 제약 조건이 수정되지 않은 경우 UIView는에 대한 호출을 건너 뜁니다 updateConstraints. setNeedsUpdateConstraint프로세스에서 제약 조건을 수정 하려면 명시 적으로 호출해야합니다 .

전화 updateConstraints하려면 다음을 수행해야합니다.

[view setNeedsUpdateConstraints];
[view setNeedsLayout]; 
[view layoutIfNeeded];

고마워, 이것은 내 문제를 해결했다. 애니메이션 전에 LayoutIfNeeded ()를 호출 할 때 임시 제약 조건이 추가 된 부모 UIView가없는 UIWindow가 있습니다. 하위 창 래퍼를 UIWindow에 추가 하고이 세 가지 메소드를 호출하면 문제가 해결되었습니다.
masterwok

setNeedsLayout 직후에 layoutIfNeeded 호출이 올바른 것으로 생각하지 않습니다. 레이아웃이 즉시 다시 그려지고 다음 업데이트주기에서 두 번째 레이아웃이 다시 그려지더라도 메소드는 동일하기 때문에.
fillky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.