获取UIViewController视图的正确边界

dem*_*733 44 xcode rotation uiviewcontroller bounds ios

我有一个iPad应用程序.在横向方向上,UIViewController视图实际宽度= 1024px和高度= 768 - 20(statusBar) - 44(navigationBar)= 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];
}
Run Code Online (Sandbox Code Playgroud)

边界是这样的:

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

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

Ric*_*chS 33

根据其他一些答案,您看到的问题是因为在轮换发生之前viewDidLoad调用.由于iPad始终以纵向模式初始化,因此如果您获得尺寸值,它们将始终为纵向尺寸 - 这与您配置的任何方向无关. viewDidLoad

为了获得规模的方向/旋转情况,得到的大小值viewDidAppear.


我并不特别理解为什么iOS不能更好地处理这个问题 - 特别是考虑到你在项目设置中定义了方向,并且在Xcode Interface Builder中.但是,我确信有一个很好的理由;-).

  • 我强烈建议**不要**使用`viewDidAppear`.您的视图在屏幕上,此时用户可以看到,您所做的更改可能会导致突然和可见的故障.它也无法帮助您在旋转期间响应视图大小的变化(等).[相反,使用`viewWillLayoutSubviews`](http://stackoverflow.com/a/42275589/2547229)(披露:链接到我的答案)这是iOS处理程序的方式. (3认同)
  • 如果用户在显示后进行旋转,则viewDidAppear将无法工作.正确的答案来自@Benjohn viewWillLayoutSubviews,无论你是否旋转它都会调用 (3认同)

Ben*_*ohn 30

如何正确地做到这一点

您的UIViewController子类应该重写该方法viewWillLayoutSubviews,另请参见此处.

调用此方法时,viewController的view大小正确,您可以在布局传递子视图之前对子视图进行任何必要的调整.

迅速

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    NSLog("bounds = \(self.view.bounds)")
}
Run Code Online (Sandbox Code Playgroud)

OBJ-C

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

文档

当视图的边界发生变化时,视图会调整其子视图的位置.您的视图控制器可以覆盖此方法以在视图布局其子视图之前进行更改.此方法的默认实现不执行任何操作.

从强调部分看,每次视图控制器的视图改变大小时,以及视图首次出现时,都会调用此方法.这使您可以正确响应旋转和其他边界更改事件

有几种方法无效

其他答案中提出的一些方法不能很好地工作,或者有严重的缺点.不幸的是,这包括选定的答案.我敦促你避免这些方法.我将通过它们讨论你不应该使用它们的原因.请不要.

  • viewDidLoadviewWillAppear-在这些电话view还没有最终的大小.你获得的大小只有通过纯粹的机会才能正确,以便误导你.
  • viewDidAppear - 这太晚了.您的视图已在屏幕上并且对用户可见.在这里进行更改将导致明显的变化/突然的故障,并将看起来业余.再一次,请 - 为了你的缘故,为了我,为了每个人的利益:不要这样做!你比那更好,你的用户也是如此.
  • UIScreen.mainScreen.bounds.size- 这是非常低的水平.你正在实现一个UIViewController,它的视图大小取决于它嵌入的控制器(导航,标签,分页,任何自定义控制器等),设备如何旋转,以及可能的屏幕分割方式多任务处理.因此,虽然您可能能够弥补所有这些并计算视图的最终大小,但如果Apple决定更改任何这些指标,您最终会遇到复杂而脆弱的代码.UIViewController如果你只是覆盖,它会为你做这一切viewWillLayoutSubviews.

除了不提供正确的信息之外,这些有问题的方法无法帮助您进行自动旋转或导致视图控制器视图更改大小的其他事件,例如多任务手势.这是你真正想要顺利处理的事情.

所以请:成为冠军.以正确的方式做到这一点.使用viewWillLayoutSubviews.每次更改尺寸都会调用您的实施,您的用户,未来的自我,团队成员和我将为您庆祝.好样的!

进一步提示

viewWillLayoutSubviews被调用时,只查看您的层次结构,将被调整到它的最终尺寸viewController.view.为此提供的是该方法的名称.它告诉你view…(你的视图控制器的根view)…WillLayout…(真的快了,但它没有发生尚未)…Subviews(根视图下的一切在它的层次).

所以子视图布局还没有发生.根目录下的每个孩子都没有有效的最终大小.您从子视图查询的任何大小信息最多都是完全错误的.

更可能,更糟糕的是,这将是误导性的正确.

恰好是您期望和需要的,因为此大小和方向的默认值,或者由于您的故事板设置.但这只是偶然的,并不是你可以依赖不同设备尺寸或方向的东西.

如果需要告知特定子视图何时更改大小并知道其确切的最终大小,通常应该覆盖该layoutSubviews特定UIView子类的方法.


luk*_*ris 15

我一直用:

CGSize sizeOfScreen = [[UIScreen mainScreen] bounds].size;
Run Code Online (Sandbox Code Playgroud)

获得屏幕的大小,并:

CGSize sizeOfView = self.view.bounds.size;
Run Code Online (Sandbox Code Playgroud)

得到view的大小.我刚刚在viewDidLoad上测试了它并返回了:

2012-07-17 10:25:46.562 Project[3904:15203] bounds = {768, 1004}
Run Code Online (Sandbox Code Playgroud)

这是正确的,因为CGSize被定义为{Width,Height}.