【问题标题】:Why am I having to manually set my view's frame in viewDidLoad?为什么我必须在 viewDidLoad 中手动设置我的视图框架?
【发布时间】:2011-10-09 01:53:20
【问题描述】:

我有一个非常基本的设置,在 UITabBarController 内有一个 UINavigationController。我想以编程方式布局该导航控制器的 rootViewController 的视图,但是当我查看 viewDidLoad 中的 self.view.frame 时,我得到了这个(例如,在 landscape 中):

1. view frame: {{20, 0}, {748, 1024}} // looks like an odd portrait mode

然后我自动旋转到纵向,我得到了这个:

2. view frame: {{0, 0}, {768, 911}}

然后当我回到横向时,框架现在是这样的:

3. view frame: {{0, 0}, {1024, 655}}

进一步的自动旋转事件将在帧值 #2 和 #3 之间翻转。

为了解决 #1 的怪异问题,我目前正在 viewDidLoad 中执行此操作:

if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) {
    self.view.frame = CGRectMake(0, 0, 768, 911);
} else {
    self.view.frame = CGRectMake(0, 0, 1024, 655);
}

我觉得我显然在这里遗漏了一些东西。为什么视图的默认框架在自动旋转回相同方向时与框架不匹配?视图框架是否未设置为初始方向?很迷茫……

我应该提一下,包括我笨拙的 hack 在内的上述所有内容都不会在视觉上改变任何东西。我有 hack 的原因是,当我将子视图布局到此视图中时,它们将基于我期望它们的位置,即导航栏下方的左上角。

我做错了什么?

更新:关闭视图上的所有自动调整大小的东西会将结果 #1 更改为:

view frame: {{0, 0}, {748, 1024}}

这似乎有点接近,但仍然不匹配#3。

【问题讨论】:

    标签: iphone ipad uiview frame viewdidload


    【解决方案1】:

    不保证 viewDidLoad 中的框架与最终显示视图时的框架相同。 UIKit 在显示之前调整视图控制器视图的框架,基于将出现的上下文。大小取决于界面方向和任何可见导航栏、标签栏、工具栏或状态栏的尺寸(它们本身的高度可以改变,例如当您打电话时)。

    这有助于理解加载和显示视图控制器的视图时会发生什么:

    1. 第一次访问视图控制器的view 属性。这可能发生在您自己的代码中,也可能发生在 UIKit 中以响应用户操作(例如选择选项卡)。

    2. UIKit 通过调用loadView(如果已定义)或通过从initWithNibName:bundle: 中指定的NIB 加载视图来延迟加载视图控制器的视图。如果两者都不存在,UIKit 只会加载一个空视图。

    3. 一旦视图及其子视图完全加载,UIKit 就会调用 viewDidLoad此时,视图的框架将是它在 NIB 或 loadView 中设置的任何内容。

    4. 需要 UIKit 来显示视图控制器的视图。同样,这可能是用户操作,例如点击选项卡,或代码中的显式方法调用,例如 pushViewController:animated:presentModalViewController:animated:

    5. UIKit 根据将要呈现的上下文调整视图的大小,如上所述。

    6. UIKit 调用 viewWillAppear:框架现在应该是要显示的尺寸了。 (?) 编辑:这可能不再适用。请参阅下面的 cmets。

    7. UIKit 显示视图,有或没有动画。

    8. UIKit 调用viewDidAppear:

    如您所见,如果您需要在视图框架呈现之前知道它的大小,viewWillAppear: 是您唯一的机会。请记住,由于各种原因,包括旋转事件或状态栏高度的变化,视图出现后此大小可能会发生变化。出于这个原因,给每个子视图一个适当的 autoresizingMask 是很重要的,以确保布局可以根据边界的任何变化进行适当的调整。

    如果您希望手动构建视图层次结构,建议在 loadView 中执行此操作。由于您在此方法中自己构建视图,因此您可以将其框架初始化为您想要的任何内容。你选择的大小并不重要,因为 UIKit 很可能会在你身上改变它。只需确保正确设置 autoresizingMasks。

    【讨论】:

    • 我对你的答案 3 有疑问。我尝试在 nib 文件中设置视图,但在 viewDidLoad 中,我的视图框架不是我在 Nib 中设置的。我在这里发布了我的问题stackoverflow.com/q/7266177/147564
    • 奇怪,我的视图直到第 8 步才有正确的框架 viewDidAppear:
    • 框架在 iOS 5.0+ 的viewDidLayoutSubviews 中可用
    • @MrRogers 在这里也一样。 viewDidAppear: 中不保证帧大小/位置。
    • 当你使用自动布局时,你应该使用 viewDidLayoutSubviews 而不是 viewWillAppear。这看起来也很有用:kevindew.me/post/18579273258/…
    【解决方案2】:

    你的类里会有一个方法

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations    return YES; }
    

    把你的框架放在这个方法中......然后它会正常工作。

    例如:

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
    {
            // Return YES for supported orientations    
            if(interfaceOrientation == UIDeviceOrientationPortrait || UIDeviceOrientationPortraitUpsideDown)
                    self.view.frame = CGRectMake(0, 0, FRAME.WIDTHinPOTRAIT, FRAME.HEIGHTinPOTRAIT);
            else if(interfaceOrientation == UIDeviceOrientationLandscapeRight || UIDeviceOrientationLandscapeLeft)
                    self.view.frame = CGRectMake(0, 0, FRAME.WIDTHinLANDSCAPE, FRAME.HEIGHTinLANDSCAPE);
    
            return YES; 
    }
    

    FRAME.WIDTH > 所需宽度 FRAME.HEIGHT > 想要的高度

    【讨论】:

    • shouldAutorotate 中调整 self.view 的大小正是 UIKit 文档所说的不应该这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 1970-01-01
    相关资源
    最近更新 更多