获取UIViewController的观点的正确界限

问题描述 投票:41回答:5

我有一个iPad应用程序。在横向取向的UIViewController认为实际宽度= 1024px和高度= 768 - 20(的状态栏。) - 44(的导航栏)= 704px

所以,我想获得这个[1024 x 704]大小和我使用self.view.bounds它。它返回[748 x 1024],这是不对的!但是,当我旋转屏幕的两倍(电流 - >肖像 - >电流),视图的边界是正确的 - [1024 x 704]

有一种观点初始化是这样的:

- (void)loadView {
    self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
    self.view.backgroundColor = [UIColor lightGrayColor];
}

和范围都得到这样的:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"bounds = %@", NSStringFromCGRect(self.view.bounds));
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    NSLog(@"bounds = %@", NSStringFromCGRect(self.view.bounds));
}

所以,问题是..我怎样才能得到正确的观点在一开始绑定?

ios xcode uiviewcontroller rotation bounds
5个回答
33
投票

按照一些其他的答案,你所看到的问题是,因为旋转发生之前viewDidLoad被调用。因为iPad总是在纵向模式初始化,如果你在viewDidLoad大小值,它们将永远是画像的大小 - 这是无论你配置的任何方位。

要获得定向/旋转发生后的尺寸,拿在viewDidAppear大小值。


我不是特别理解为什么iOS不处理这更好的 - 特别是考虑到在项目设置中定义的方向,并且,在Xcode界面生成器。但是,我敢肯定有一个很好的理由;-)。


27
投票

How to do this correctly

UIViewController子类应该覆盖的方法viewWillLayoutSubviewssee also here

当这个方法被调用时,的viewController的view有其正确的大小,并可以进行任何必要的调整,之前的布局传过来的子视图子视图。

Swift

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    NSLog("bounds = \(self.view.bounds)")
}

Obj-C

- (void)viewWillLayoutSubviews {
    [super viewWillLayoutSubviews];
    NSLog(@"bounds = %@", NSStringFromCGRect(self.view.bounds));
}

Documentation

当一个视图边界改变,视图调整其子视图的位置。您的视图控制器可以重写此方法来更改视图勾画出它的子视图之前。此方法的默认实现不执行任何操作。

当你从强调的部分看,这种方法称为每次视图控制器的视图改变大小,以及当视图第一次出现。这使您可以正确地响应旋转和其他边界改变事件

Several ways that don't work

在其他的答案提出了几种方法效果不好,或有严重的缺点。不幸的是,这包括所选择的答案。我劝你避免这些方法。我会通过他们去讨论,你不应该使用它们的原因。请不要。

  • viewDidLoadviewWillAppear - 在这些调用view还没有最终的大小。你得到的大小将永远只能是纯偶然正确的,从而误导你。
  • viewDidAppear - 这是为时已晚。您的观点是已经在屏幕上对用户可见。这里制作的变化会引起明显的变化/突发性故障,并期待业余。再次,请 - 为您着想,为我的缘故,大家的缘故:不这样做!你比这更好的等等都是你的用户。
  • UIScreen.mainScreen.bounds.size - 这是非常低的水平。你实施UIViewController及其视图的大小取决于它嵌套在(导航,制表符,寻呼,任何定制控制器,等等),该装置是如何旋转,并且潜在地,如何在屏幕已被划分为所述控制器对于多任务处理。所以,虽然你也许能够弥补所有这些和计算你的观点的最终大小,你会复杂和脆弱的代码,如果苹果决定更改这些指标可以轻松突破而告终。 UIViewController会做这一切为你,如果你只是覆盖viewWillLayoutSubviews

除了没有提供正确的信息,这些问题的方法不会帮你自动旋转或其他事件,导致视图控制器的视图改变大小,如多任务手势。这是你真正想要顺利处理的东西。

所以请:是冠军。做正确的方式。使用viewWillLayoutSubviews。你的实现将被调用为各种规模的变化,你的用户,未来的自己,团队成员和我将庆祝你。好样的!

Further tips

viewWillLayoutSubviews被调用时,在您的层次结构中的唯一视图,将被调整到它的最终尺寸为viewController.view。白送因为这是在方法的名称。它告诉你view…(您的视图控制器的根view…WillLayout…(真的快了,但它没有发生过)…Subviews(根视图下,一切都在它的层次其他人)。

因此,子视图布局还没有发生。在根目录下每个孩子都还没有一个有效的最终大小。您从子视图查询的任何大小的信息将在最好的完全错误的。

更有可能的是,更糟极大,这将是误导正确的。

这恰好是你所期望的,在这个大小和方向,或由于你的故事板设置需要因违约。不过,这只是偶然,是不是你可以依靠不同的器件尺寸或方向。

如果你需要在一个特定的子视图改变大小被告知,并且知道它确切的最终大小,你通常应该重写特定layoutSubviews子类的UIView方法。


13
投票

我一直使用:

CGSize sizeOfScreen = [[UIScreen mainScreen] bounds].size;

得到屏幕的大小,以及:

CGSize sizeOfView = self.view.bounds.size;

得到view的大小。我刚才测试了viewDidLoad中和它返回:

2012-07-17 10:25:46.562 Project[3904:15203] bounds = {768, 1004}

这是正确的,因为CGSize被定义为{宽度,高度}。


2
投票

这是我在过去的项目中找到:self.view的框架将viewDidLoad中后进行调整,根据如果屏幕上有导航栏等。

因此,也许你想使用viewDidLoad中(也许在viewWillAppear中或viewDidAppear)后的值或者通过的。减去条的高度手动调节。


2
投票

我就遇到了这个问题,并发现得到的边界在viewDidAppear我需要工作。

© www.soinside.com 2019 - 2024. All rights reserved.