layoutSubviews는 언제 호출됩니까?


264

layoutSubview애니메이션 중에 메시지 가 표시되지 않는 사용자 정의보기가 있습니다.

화면을 채우는 뷰가 있습니다. 탐색 표시 줄의 높이를 변경하면 인터페이스 빌더에서 올바르게 크기가 조정되는 화면 하단에 사용자 정의 하위보기가 있습니다. layoutSubviews뷰가 생성 될 때 호출되지만 다시는 호출되지 않습니다. 내 소견이 올바르게 배치되었습니다. 통화 중 상태 표시 줄을 끄면 layoutSubviews기본보기가 크기 조정에 애니메이션을 적용하더라도 하위보기 가 전혀 호출되지 않습니다.

어떤 상황에서 layoutSubviews실제로 불려지 는가?

나는 한 autoresizesSubviews설정 NO내 사용자 정의보기를. 그리고 Interface Builder에는 상단 및 하단 스트럿과 수직 화살표가 있습니다.


퍼즐의 또 다른 부분은 창을 열쇠로 만들어야한다는 것입니다.

[window makeKeyAndVisible];

그렇지 않으면 하위 뷰의 크기가 자동으로 조정되지 않습니다.

답변:


492

비슷한 질문이 있었지만 대답 (또는 인터넷에서 찾을 수있는 것)에 만족하지 못했기 때문에 실제로 시도해 보았습니다.

  • initlayoutSubviews(duh)라고 부르지 않습니다
  • addSubview:원인 layoutSubviews추가되는 뷰라고하는 뷰는 그것 (목표 뷰)을 첨가하고, 타겟의 모든 파단되는 것
  • 도면 setFrame 지능적 호출 layoutSubviews프레임의 크기 파라미터가 다른 경우에만 해당 프레임 세트를 갖는보기
  • UIScrollView를 스크롤 layoutSubviews하면 scrollView 및 그 superview에서 호출됩니다.
  • 장치를 회전 layoutSubview하면 상위 뷰 에서만 호출 (응답 viewControllers 기본 뷰)
  • 뷰 크기를 조정하면 layoutSubviews수퍼 뷰 가 호출 됩니다.

내 결과 -http : //blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/


1
좋은 대답입니다. 나는 항상 궁금했다 layoutSubviews. 않는 initWithFrame:원인은 layoutSubviews호출 할?
Robert

2
@Robert-나는 initWithFrame을 사용하고 있었다.
BadPirate

8
@BadPirate : . 크기를 조정하면 내 실험에 따르면, view1.1이 호출 layoutSubviewsview1다음 layoutSubviewsview1.1. 이 호출은 수퍼 뷰에 무기한으로 전파되지 않으며 on 및 view1.1.1호출에서만 호출 layoutSubviews됩니다 . 크기를 변경하지 않고 이동해도 아무 것도 호출하지 않습니다 . view1.1view1.1.1layoutSubviews
João Portela

1
viewDidLoad는 UIView에서 호출되지 않습니다 (그러나 UIViewController). 보기 UIView가 초기화 된 후로드가 호출되었습니다.
BadPirate

2
내 실험을 바탕으로, 두 번째 규칙은 정확하지있을 수 있습니다 : 내가 추가 할 때 view1.2view1, layoutSubviewsview1.2view1라고하지만 layoutSubviews의이 view1.1호출되지 않습니다. ( view1.1view1.2의 파단이다 view1). 즉, 대상 뷰의 모든 하위 뷰가 layoutSubviewsmethod 라고하는 것은 아닙니다 .
HongchaoZhang

96

@BadPirate의 이전 답변을 바탕으로 조금 더 실험하고 설명 / 수정 사항을 제시했습니다. 다음 layoutSubviews:과 같은 경우에만 뷰에서 호출됩니다.

  • 자체 경계 (프레임 아님)가 변경되었습니다.
  • 직접 서브 뷰 중 하나의 경계가 변경되었습니다.
  • 서브 뷰가 뷰에 추가되거나 뷰에서 제거됩니다.

관련 정보 :

  • 범위는 다른 원점을 포함 하여 새 값이 다른 경우에만 변경된 것으로 간주됩니다 . 특히 layoutSubviews:경계의 원점을 변경하여 스크롤을 수행하므로 UIScrollView가 스크롤 될 때마다 호출됩니다.
  • 프레임을 변경하면 크기가 변경된 경우에만 경계가 변경됩니다. 이것이 경계 속성으로 전파되는 유일한 것입니다.
  • 뷰 계층 구조에 아직없는 뷰의 경계가 변경 layoutSubviews: 되면 뷰가 결국 뷰 계층 구조에 추가 될 때 호출됩니다 .
  • 그리고 완전성을 위해 :이 트리거는 layoutSubviews를 직접 호출 하지 않고 오히려 setNeedsLayout플래그를 설정 / 발생시키는 call을 호출 합니다. 실행 루프의 각 반복은 보기 계층의 모든보기 대해이 플래그가 검사됩니다. 플래그가 발견 된 각 뷰에 대해 layoutSubviews:호출되고 플래그가 재설정됩니다. 계층 구조보다 높은 뷰는 먼저 확인 / 호출됩니다.

5
이 답변을 충분히 찬성 할 수 없습니다. 최고 답변이어야합니다. 주어진 세 가지 규칙 만 있으면됩니다. 이 규칙이 완벽하게 설명하지 않은 layoutSubview 동작을 본 적이 없습니다.
Pärserk

1
직접 subview의 경계가 변경되면 layoutSubviews가 호출되지 않는다고 생각합니다. layoutSubviews 호출은 테스트의 부작용 일뿐입니다. 하위 뷰 경계가 변경 될 때 layoutSubviews가 호출되지 않는 경우가 있습니다. 그의 답변은 실험이 아닌 Apple의 문서를 기반으로하기 때문에 frogcjn의 답을 확인하십시오.
Simon Backx

19

https://developer.apple.com/library/prerelease/tvos/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1

보기에서 다음 이벤트가 발생할 때마다 레이아웃 변경이 발생할 수 있습니다.

ㅏ. 뷰의 경계 사각형 크기가 변경됩니다.
비. 일반적으로 루트 뷰의 경계 사각형에서 변경을 트리거하는 인터페이스 방향 변경이 발생합니다.
씨. 뷰의 레이어와 관련된 핵심 애니메이션 하위 레이어 세트가 변경되고 레이아웃이 필요합니다.
디. 응용 프로그램은  뷰 의 setNeedsLayout 또는  layoutIfNeeded메소드를 호출하여 레이아웃이 발생  하도록합니다.
이자형. 응용 프로그램은 setNeedsLayout 뷰의 기본 레이어 객체의 메서드를 호출하여 레이아웃을 강제  합니다.


또한 뷰가 뷰 스택에 아직 추가되지 않은 경우 이러한 이벤트 중 어느 것도 호출되지 않습니다. 이 단어를 "can"이라는 단어와 함께 포함 시키지만, 특히 해당 이벤트 중 하나에 의해 레이아웃이 필요한 것으로 표시되면 응용 프로그램 기본 스레드의 다음 사용 가능한주기에서 호출됩니다.
user1122069

13

에있는 점의 일부 BadPirate의 대답은 부분적으로 만 해당 :

  1. 대한 addSubView포인트

    addSubview 추가중인보기, 추가중인보기 (대상보기) 및 대상의 모든 하위보기에서 layoutSubviews를 호출합니다.

    뷰의 (대상 뷰) 자동 크기 조정 마스크에 따라 다릅니다. 자동 크기 조정 마스크가 켜져 있으면 각에서 layoutSubview가 호출됩니다 addSubview. 자동 크기 조정 마스크가 없으면 view의 (대상보기) 프레임 크기가 변경 될 때만 layoutSubview가 호출됩니다.

    예 : 프로그래밍 방식으로 UIView를 만든 경우 (기본적으로 자동 크기 조정 마스크가 없음) LayoutSubview는 UIView 프레임이 모두 변경되지 않은 경우에만 호출됩니다 addSubview.

    이 기술을 통해 응용 프로그램의 성능도 향상됩니다.

  2. 장치 회전 지점

    장치를 회전하면 상위 뷰 (응답 viewController의 기본 뷰)에서 layoutSubview 만 호출합니다.

    이는 VC가 VC 계층 (root at window.rootViewController) 에있을 때만 해당 될 수 있습니다 . 가장 일반적인 경우입니다. iOS 5에서 VC를 만들지 만 다른 VC에 추가되지 않으면 장치가 회전 할 때이 VC가 통지를받지 않습니다. 따라서 layoutSubviews를 호출해도 해당 뷰가 표시되지 않습니다.


9

시뮬레이션 된 화면 요소가 설정된 뷰 (상태 표시 줄 등)에서 스프링을 변경할 수 없다는 Interface Builder의 주장에 대한 솔루션을 추적했습니다. 스프링이 메인 뷰에서 꺼 졌기 때문에 뷰가 크기를 변경할 수 없으므로 호출 막대가 나타날 때 전체가 아래로 스크롤되었습니다.

시뮬레이션 된 기능을 끄고보기의 크기를 조정하고 스프링을 올바르게 설정하면 애니메이션이 발생하고 메서드가 호출되었습니다.

이를 디버깅 할 때의 또 다른 문제점은 메뉴를 통해 통화 중 상태가 전환 될 때 시뮬레이터가 앱을 종료한다는 것입니다. 앱 종료 = 디버거 없음


뷰의 크기를 조정할 때 layoutSubviews가 호출된다고 말하고 있습니까? 난 항상 ... 그렇지 않은 가정
안드레이 Tarantsov에게

그것은. 뷰의 크기가 조정되면 하위 뷰로 무언가를 수행해야합니다. 제공하지 않으면 스프링, 스트럿 등을 사용하여 자동으로 이동시킵니다.
Steve Weller

8

호출 [self.view setNeedsLayout]; 의 ViewController에서하는 전화 viewDidLayoutSubviews에 있습니다


5

layoutIfNeeded를 보셨습니까?

설명서 스 니펫은 다음과 같습니다. 애니메이션 중에이 메서드를 명시 적으로 호출하면 애니메이션이 작동합니까?

layoutIfNeeded 필요한 경우 하위보기를 배치합니다.

- (void)layoutIfNeeded

토론이 방법을 사용하여 그리기 전에 하위 뷰의 레이아웃을 강제로 적용하십시오.

사용 가능 iPhone OS 2.0 이상에서 사용 가능합니다.


2

OpenGL 앱을 SDK 3에서 4로 마이그레이션 할 때 layoutSubviews는 더 이상 호출되지 않았습니다. 많은 시행 착오 끝에 마침내 MainWindow.xib를 열고 Window 객체를 선택했습니다. 인스펙터에서 Window Attributes 탭 (가장 왼쪽)을 선택하고 "Visible at launch"를 체크했습니다. SDK 3에서는 여전히 layoutSubViews 호출을 유발하지만 4에서는 발생하지 않는 것으로 보입니다.

6 시간의 좌절은 끝났다.


창 열쇠를 만들었습니까? 그렇지 않으면 모든 종류의 흥미로운 일이 발생하지 않을 수 있습니다.
Steve Weller 2016 년

-2

layoutSubviews호출되지 않을 때 다소 모호하지만 잠재적으로 중요한 경우 는 다음과 같습니다.

import UIKit

class View: UIView {

    override class var layerClass: AnyClass { return Layer.self }

    class Layer: CALayer {
        override func layoutSublayers() {
            // if we don't call super.layoutSublayers()...
            print(type(of: self), #function)
        }
    }

    override func layoutSubviews() {
        // ... this method never gets called by the OS!
        print(type(of: self), #function)
    }
}

let view = View(frame: CGRect(x: 0, y: 0, width: 100, height: 100))

1
이 답변이 왜 여기에 있습니까?
Dominik Bucher
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.