2012-03-02 5 views
36

landscape 모드에서 ViewController를 시작하면 (viewDidLoad가 호출 된 후) 세로 모드의 프레임 크기를 대신 제공하는 프레임을 인쇄합니다.UIViewController가 잘못된 프레임을 반환합니까?

버그가 제안 되었습니까?

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    NSLog(@"%@", NSStringFromCGRect(self.view.frame)); 
    // Result is (0, 0 , 768, 1024) 
} 
+1

그러면 viewDidAppear은 어떻습니까? – Luke

+1

viewDid 잘 작동했습니다. – aryaxt

답변

157

이해할 수없는 몇 가지 사항이 있습니다.

먼저, 펜촉을 넣은 직후 시스템에서 viewDidLoad을 보냅니다. 뷰 계층에 뷰를 아직 추가하지 않았습니다. 따라서 장치의 회전을 기준으로보기의 크기를 조정하지 않았습니다.

둘째,보기의 프레임은 수퍼바이저의 좌표 공간에 있습니다. 이것이 루트보기 인 경우 수퍼 뷰는 UIWindow입니다 (일단 시스템이보기 계층에보기를 추가하면). UIWindow은 하위 뷰의 변환을 설정하여 회전을 처리합니다. 즉, 뷰 프레임이 반드시 예상 한 것과 다를 수 있습니다. 여기

은 세로 방향으로 뷰 계층의 :

(lldb) po [[UIApp keyWindow] recursiveDescription] 
(id) $1 = 0x09532dc0 <UIWindow: 0x9632900; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x96329f0>> 
    | <UIView: 0x9634ee0; frame = (0 20; 768 1004); autoresize = W+H; layer = <CALayer: 0x9633b50>> 

여기에 가로 왼쪽 방향으로 뷰 계층 구조입니다 : 가로 방향으로, 프레임 크기가

(lldb) po [[UIApp keyWindow] recursiveDescription] 
(id) $2 = 0x09635e70 <UIWindow: 0x9632900; frame = (0 0; 768 1024); layer = <UIWindowLayer: 0x96329f0>> 
    | <UIView: 0x9634ee0; frame = (20 0; 748 1024); transform = [0, -1, 1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x9633b50>> 

공지 것을 748 X 1024 , 1024x748입니다.

루트보기 인 경우 보려는 대상은보기의 b입니다. ounds :

(lldb) p (CGRect)[0x9634ee0 bounds] 
(CGRect) $3 = { 
    (CGPoint) origin = { 
    (CGFloat) x = 0 
    (CGFloat) y = 0 
    } 
    (CGSize) size = { 
    (CGFloat) width = 1024 
    (CGFloat) height = 748 
    } 
} 

아마도보기의 변환, 프레임 및 경계가 언제 업데이트되는지 알고 싶을 것입니다. 뷰 컨트롤러는 뷰를로드 할 때 인터페이스가 가로 방향에있는 경우,이 순서대로 메시지가 나타납니다 :

{{0, 0}, {768, 1004}} viewDidLoad 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} viewWillAppear: 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {768, 1004}} willRotateToInterfaceOrientation:duration: 
{{0, 0}, {1024, 748}} viewWillLayoutSubviews 
{{0, 0}, {1024, 748}} layoutSubviews 
{{0, 0}, {1024, 748}} viewDidLayoutSubviews 
{{0, 0}, {1024, 748}} willAnimateRotationToInterfaceOrientation:duration: 
{{0, 0}, {1024, 748}} shouldAutorotateToInterfaceOrientation: 
{{0, 0}, {1024, 748}} viewDidAppear: 

당신이 이전 willRotateToInterfaceOrientation:duration:를받을 후에는 뷰의 경계를 변경할 것을 볼 수 있습니다 당신 viewWillLayoutSubviews을 받으십시오.

viewWillLayoutSubviewsviewDidLayoutSubviews 방법은 iOS 5.0에 새로운 기능입니다.

메시지는보기 컨트롤러가 아닌보기로 전송되므로 사용하려면 사용자 지정 UIView 하위 클래스를 만들어야합니다.

+0

감사합니다. 훌륭한 정보 – aryaxt

+1

이것은 훌륭한 설명입니다. – schellsan

+1

내가들은 최고의 설명 중 하나. 감사합니다 – Jon

2

다음은 깨끗한 해결책입니다.

동일한 문제가 발생하여 내 앱 전체에 frame을 사용해야한다고 주장합니다. 루트보기 컨트롤러에 대한 예외를 만들고 싶지 않습니다. 루트 뷰 컨트롤러의 frame이 세로 크기 인 을 표시했지만 모든 하위 뷰의 가로 크기가 인 것으로 나타났습니다.

다르게 동작하는 루트보기 컨트롤러 만 있으므로 표준 비어있는보기 컨트롤러를 루트보기 컨트롤러로 설정하고 여기에 사용자 지정보기 컨트롤러를 추가 할 수 있습니다. (아래 코드.)

사용자 지정보기 컨트롤러에서 의도 한대로 frame을 사용할 수 있습니다.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    // Override point for customization after application launch. 

    self.window.rootViewController = [[UIViewController alloc] init]; 

    [self.window makeKeyAndVisible]; 

    self.viewController = [[ViewController alloc] initWithNibName:nil bundle:nil]; 
    [self.window.rootViewController addChildViewController:self.viewController]; 
    [self.window.rootViewController.view addSubview:self.viewController.view]; 

    return YES; 
} 
관련 문제