viewWillAppear : 및 viewDidAppear 간의 뷰 프레임 변경 :


85

나는 연결된 내 응용 프로그램에서 이상한 행동을 발견 IBOutlet받는 내보기 컨트롤러의 호출 사이의 연결 뷰의 프레임이 viewWillAppear:viewDidAppear:. 내 UIViewController하위 클래스 의 관련 코드는 다음과 같습니다 .

-(void)viewWillAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

-(void)viewDidAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

결과 로그 출력 :

MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 0; 0 0); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 44; 320 416); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>

두 호출간에 프레임이 변경되고 있음을 명확하게 보여줍니다. viewDidLoad방법 의 뷰로 설정하고 싶었지만 화면에 나타날 때까지 내용을 변경할 수 없다면 꽤 쓸모없는 것 같습니다. 무슨 일이 일어날까요?


2
자동 레이아웃을 사용하고 있습니까? 인터페이스 빌더에서 또는 프로그래밍 방식으로이보기를 추가하고 있습니까?
Andrea

자동 레이아웃이 활성화되고이보기는 스토리 보드의 IB에서 생성됩니다.
Jumhyn 2013

1
저는 스토리 보드를 사용한 적이 없지만 아마도 정확할 것입니다. 뷰의 자동 레이아웃 프레임 사용은 자동 레이아웃 엔진이 계산을 시작할 때 설정됩니다. 뷰 컨트롤러의-(void) viewDidLayoutSubviews mpethod 직후에 동일한 것을 요청하십시오.
Andrea

이는 적시에 이벤트를 성공적으로 트리거하지만 뷰에서 애니메이션을 수행 할 때마다 해당 메서드도 호출됩니다.
Jumhyn 2013

1
viewDidLayoutSubviews올바른 방법이었습니다. 메인 뷰의 프레임을 변경할 때마다 메서드가 다시 호출되지 않도록 모든 콘텐츠를 하위 뷰에 넣어야했습니다.
Jumhyn jul.

답변:


111

Autolayout뷰의 GUI를 디자인하고 개발하는 방법에 큰 변화를 가져 왔습니다. 주요 차이점 중 하나는 autolayout뷰 크기를 즉시 변경하지 않고 트리거 된 경우에만 특정 시간에 의미하지만 제약 조건을 즉시 다시 계산하거나 레이아웃을 "필요한"것으로 표시하도록 강제 할 수 있다는 것입니다. 처럼 작동합니다 -setNeedDisplay.
저에게 큰 도전은 우리가 더 이상 자동 크기 조정 마스크를 사용할 필요가 없다는 것을 이해하고 받아들이는 것이었고, 프레임은 뷰를 배치하는 데 쓸모없는 속성이되었습니다. 더 이상 뷰 포지션에 대해 생각할 필요는 없지만 서로 관련된 공간에서 어떻게보고 싶은지 생각해야합니다.
오래된 자동 크기 조정 마스크와 자동 레이아웃을 혼합하려면 문제가 발생합니다. 우리는 곧 자동 레이아웃 구현에 대해 생각하고 자동 레이아웃을 기반으로하는 뷰 계층 구조에서 이전 접근 방식을 혼합하지 않도록해야합니다.
뷰 컨트롤러의 메인 뷰와 같이 자동 크기 조정 마스크 만 사용하는 컨테이너 뷰를 사용하는 것이 좋지만 혼합하지 않는 것이 좋습니다.
저는 스토리 보드를 사용한 적이 없지만 아마도 정확할 것입니다. 자동 레이아웃을 사용하면 자동 레이아웃 엔진이 계산을 시작할 때 뷰 프레임이 설정됩니다. - (void)viewDidLayoutSubviews뷰 컨트롤러의 수퍼 메서드 직후에 동일한 것을 요청하십시오 .
이 메서드는 자동 레이아웃 엔진이 뷰의 프레임 계산을 마치면 호출됩니다.


5
-(void) viewDidLayoutSubviews가 답입니다! 감사합니다!
FrizzTheSnail 2015

이 대답은 정말 정확하지 않습니다. 예, 당연히 5 년 동안은 자동 레이아웃을 사용해야합니다. 그러나 "사용자에게 표시되기 직전에"화면에 무언가를 추가해야하는 상황 ( autolayout 사용 )이 많이 있습니다. (viewDidAppear에서 수행하면 깜박임이 발생합니다. viewWillAppear에서 수행하면 위치가 잘못됩니다.) 실제 대답은 실제로 viewDidLayoutSubviews를 사용하는 것입니다.
Fattie

add something on a screen, "just before it appears to the user". The actual answer is indeed to use viewDidLayoutSubviews.... 당신은 그 뷰를 많이 보여줄 것입니다
Andrea

156

로부터 문서 :

viewWillAppear:

뷰 컨트롤러에 뷰가 뷰 계층 구조에 추가 될 예정임을 알립니다.

viewDidAppear:

뷰가 뷰 계층에 추가되었음을 뷰 컨트롤러에 알립니다.

결과적으로 하위 뷰의 프레임은 아직에서 설정되지 않았습니다 viewWillAppear.

보기가 화면에 표시되기 전에 UI수정 하는 적절한 방법 은 다음과 같습니다.

viewDidLayoutSubviews

뷰 컨트롤러에 뷰가 하위 뷰를 배치했음을 알립니다.


2
으, 짜증나 네요. 문서의 문구조차도 viewWillApepar : 및 viewDidAppear :가 서로 직접적으로 발생하는 것처럼 보입니다.
Jumhyn 2013

이 답변을 기다리는 2 개월 ... 감사합니다! 대단히 감사합니다!
Rafael Ruiz Muñoz

6
viewDidLayoutSubviews항상 동일한 프레임으로 호출되는 것은 아니지만 여러 번 호출 된다는 점에 유의해야합니다 (첫 번째 호출에서 CGRectZero로 호출되는 경우도 있습니다). 추가 된 모든 하위보기 및보기의 기타 변경 사항에 대해 호출됩니다.
bauerMusic 2015

나는 하루 종일 (viewDidLayoutSubviews가 뷰를 닫을 때를 포함하여 여러 번 호출 됨) ef를 말하고 논리를 if 문에 넣고 true로 설정되는 부울을 만들었습니다. 코드가 한 번 실행되었습니다. 더 깨끗한 방법이 있어야한다고 생각하지만 이미 너무 많은 시간이 가라 앉았습니다.
솔레노이드

우리는 이것의 바닥에 도달해야합니다! viewDidLayoutSubviews는 seNeedDisplay이 작동하지 않는, 끔찍
YARO

9

요구

self.scrollView.layoutIfNeeded ()

당신의 viewWillAppear방법에. 나중에 프레임에 액세스 할 수 있으며 인쇄 한 것과 동일한 값을 갖게됩니다.viewDidAppear


1
아니요, 이것은 올바르지 않습니다. 예 : 화면에 내비게이션 바가 있습니다 (내비게이션 컨트롤러에서). layoutIfNeeded () 후에도 navbar의 높이가 포함되지 않으므로 프레임 크기가 변경됩니다.
xaphod

이는 IS 있는 ScrollView 프레임의 수퍼 내의 제한에 연결되는 경우에는 뷰 레이아웃 호출 계층에 걸쳐 일치하도록있는 ScrollView 프레임 사이즈의 재 계산을 강제하는 좋은 방법.
smakus

4

제 경우에는 모든 프레임 관련 메서드를

override func viewWillLayoutSubviews()

완벽하게 작동했습니다 (스토리 보드에서 제약 조건을 수정하려고했습니다).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.