2012-07-17 53 views
34

我有一个iPad应用程序。在横向方向上,UIViewController的视图实际宽度= 1024px和height = 768-20(statusBar) - 44(navigationBar)= 704px获取UIViewController视图的正确范围

所以我想得到这[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)); 
} 

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

回答

29

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

要获得之后的尺寸发生定向/旋转,请在viewDidAppear中获取尺寸值。


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

+1

如果你正在创建大视图,可能会延迟视图外观,你可以通过使用'viewWillAppear'减少延迟 – 2014-08-09 08:07:26

+0

我试过viewWillAppear,它不能按要求工作,看来边界计算是在视图出现之后完成的 – Billy 2016-05-07 18:17:22

+1

我强烈建议**不要**使用'viewDidAppear '你的视图在屏幕上,用户可以看到这一点,你做的改变会引起突然和可见的毛刺,它也不会帮助你响应旋转期间视图大小的变化(等等)。 'viewWillLayoutSubviews'](http://stackoverflow.com/a/42275589/2547229)(披露:链接到我的答案)这是iOS处理这个的方式。 – Benjohn 2017-02-16 13:52:57

2

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

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

+0

我已经在'viewDidLoad'方法中使用它,并且在它之后。直到我旋转屏幕,边界仍然存在错误。手动减法是不好的解决方案,因为应用程序是针对所有设备和方向的。 – demon9733 2012-07-17 13:10:21

+3

你会在viewDidLoad之后使用它吗?在我的情况下,viewDidAppear将返回正确的大小。 – Selkie 2012-07-17 13:22:17

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被定义为{宽度,高度}这是正确的。

+1

是的,它只在旋转后才起作用:( – demon9733 2012-07-17 13:28:38

+0

这很奇怪,你在viewDidLoad中获得大小的事实应该不重要,因为视图“已经加载” – Luke 2012-07-17 13:33:22

2

我遇到了这个问题,发现获取viewDidAppear的边界符合我的需求。

12

如何做到这一点正确

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

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

文档

当视图的边界改变,视图调整它的子视图的位置。您的视图控制器可以覆盖此方法以在视图布局其子视图之前进行更改。此方法的默认实现不做任何事情。

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

几个错误方法可以做到通过这里 其他答案建议不工作这

几种方法以及 是彻底打破。不幸的是,这包括选定的答案。你真的不应该使用这些方法。他们在这里,原因是你不应该使用它们。请不要。

  • viewDidLoadviewWillAppear - 在这些调用view还没有最终的大小。 你得到的大小将永远是纯粹的机会正确的,以误导你。请求,我求求你,不要使用这些方法。
  • viewDidAppear - 这太晚了。 您的观点已经在屏幕上显示给用户。在这里进行更改会导致可见的变化/突然的故障,并且看起来像可怕的业余时间垃圾。再一次请 - 为了你,为了我的缘故,大家的为什么不这样做!你比这更好,你的用户也是如此。
  • UIScreen.mainScreen.bounds.size - 这是极端低级别。你正在实现一个UIViewController,其视图的大小取决于它嵌套在其中的控制器(导航,选项卡,分页,任何自定义控制器等),设备旋转的方式以及屏幕如何拆分多任务处理。所以,虽然你可能能够弥补所有这些,并计算你的观点的最终大小,你会最终得到复杂和脆弱的代码。 UIViewController为你做了这一切,如果你只是覆盖viewWillLayoutSubviews

除了没有提供正确的信息,这些方法不会帮助你,支持自动旋转或者使视图控制器的视图改变大小如多任务手势的其他事件。这是你真正想要处理的事情。

所以请:成为冠军。以正确的方式去做。使用viewWillLayoutSubviews。你的实施将被要求每一个尺寸的变化,你的用户,未来的自我,团队成员和我会为你庆祝。好样的!

进一步提示

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

所以子视图布局还没有发生! 孩子根还有一个有效的最后大小。从子视图查询的任何大小的信息将是最好的完全错误。

更可能的是,和无限更差,它将是误导性更正

发生是您期望和需要的,因为此尺寸和方向的默认设置,或者由于您的故事板设置。但这只是偶然的,并不是你可以依靠不同的设备尺寸或方向。

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

+0

感谢您的回答!为了澄清,你是说如果我们想知道类UIView的子视图的大小,唯一正确的方法是重写它的'layoutSubviews'方法(这将需要创建一个自定义类)? – Crashalot 2017-12-08 00:08:22

+0

@Crashalot覆盖对于展示子项的子类是有意义的。但是,如果您经常要编写此行为而不是覆盖现有视图类,则可能会产生问题。我采取的一种方法是创建一个特定的'UIView'子类,'BoundsSenderView',_only_具有将'layoutSubviews'转发给某些注入的'boundsListener'处理程序的行为。它不会显示任何内容或响应触摸等。然后,您可以使用自动布局将其固定在您想要的大小的视图上,并且在更改大小时您将获得回调。 – Benjohn 2017-12-08 10:28:59

+0

可能还有其他方法可以在布局后获得子视图的大小,但我并不知道它们。您需要连接完成的完整版式传递。 – Benjohn 2017-12-08 10:31:56