2012-03-02 85 views
36

当我开始我的ViewController在landscape模式(viewDidLoad中被调用后),我打印它给我的肖像模式帧大小,而不是框架。UIViewController返回无效帧?

这是一个错误有什么建议?

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

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

那么viewDidAppear呢? – Luke 2012-03-02 20:12:49

+1

viewDidAppear工作正常 – aryaxt 2012-03-05 04:31:56

回答

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×1024 ,不是 1024 x 748.

你可能想看看,如果这是你的根视图,是视图的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新增的。

layoutSubviews消息发送到视图,而不是视图控制器,所以如果你想使用它,你将需要创建一个自定义的UIView子类。

+0

非常感谢 – aryaxt 2012-03-05 04:32:13

+1

这是一个很好的解释。 – schellsan 2012-04-12 18:44:00

+1

我听说过的最好的解释之一。谢谢 – Jon 2012-10-07 13:07:18

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; 
}