UIViewController 返回无效帧? [英] UIViewController returns invalid frame?

查看:23
本文介绍了UIViewController 返回无效帧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在 landscape 模式下启动我的 ViewController 时(在调用 viewDidLoad 之后),我打印了它给我纵向模式的帧大小的帧.

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

- (void)viewDidLoad{[超级viewDidLoad];NSLog(@"%@", NSStringFromCGRect(self.view.frame));//结果是 (0, 0, 768, 1024)}

解决方案

有些事情你不明白.

首先,系统会在您的笔尖加载后立即向您发送viewDidLoad.它甚至还没有将视图添加到视图层次结构中.所以它也没有根据设备的旋转调整你的视图大小.

其次,视图的框架位于其父视图的坐标空间中.如果这是您的根视图,它的超级视图将是 UIWindow(一旦系统实际将您的视图添加到视图层次结构中).UIWindow 通过设置其子视图的变换来处理旋转.这意味着视图的框架不一定是您所期望的.

这是纵向视图层次结构:

(lldb) po [[UIApp keyWindow] recursiveDescription](id) $1 = 0x09532dc0 

这里是横向向左方向的视图层次结构:

(lldb) po [[UIApp keyWindow] recursiveDescription](id) $2 = 0x09635e70 <UIWindow: 0x9632900;帧 = (0 0; 768 1024);层 = <UIWindowLayer: 0x96329f0>>|<UIView: 0x9634ee0;框架 = (20 0; 748 1024);变换 = [0, -1, 1, 0, 0, 0];自动调整大小 = W+H;层=<CALayer:0x9633b50>>

请注意,在横向模式下,框架大小为 748 x 1024,不是 1024 x 748.

如果这是您的根视图,您可能想查看的是视图的边界:

(lldb) p (CGRect)[0x9634ee0 bounds](CGRect) $3 = {(CGPoint) 原点 = {(CGFloat) x = 0(CGFloat) y = 0}(CGSize) 大小 = {(CGFloat) 宽度 = 1024(CGFloat) 高度 = 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}} 布局子视图{{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 子类.

When I start my ViewController in landscape mode (After viewDidLoad is called), I print the frame it's giving me the frame size for portrait mode instead.

Is this a bug any suggestions?

- (void)viewDidLoad
{
   [super viewDidLoad];

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

解决方案

There are a couple of things that you don't understand.

First, the system sends you viewDidLoad immediately after loading your nib. It hasn't even added the view to the view hierarchy yet. So it hasn't resized your view based on the device's rotation either.

Second, a view's frame is in its superview's coordinate space. If this is your root view, its superview will be the UIWindow (once the system actually adds your view to the view hierarchy). The UIWindow handles rotation by setting the transform of its subview. This mean that the view's frame will not necessarily be what you expect.

Here's the view hierarchy in portrait orientation:

(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>>

and here's the view hierarchy in landscape-left orientation:

(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>>

Notice that in landscape orientation, the frame size is 748 x 1024, not 1024 x 748.

What you probably want to look at, if this is your root view, is the view's bounds:

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

Presumably you want to know when the view's transform, frame, and bounds get updated. If the interface is in a landscape orientation when your view controller loads its view, you will receive messages in this order:

{{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:

You can see that your view's bounds change after you receive willRotateToInterfaceOrientation:duration: and before you receive viewWillLayoutSubviews.

The viewWillLayoutSubviews and viewDidLayoutSubviews methods are new to iOS 5.0.

The layoutSubviews message is sent to the view, not the view controller, so you will need to create a custom UIView subclass if you want to use it.

这篇关于UIViewController 返回无效帧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆