当我在landscape
模式下启动ViewController时(调用viewDidLoad之后),我打印框架,它为我提供了纵向模式的帧大小。
这是一个错误的建议吗?
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"%@", NSStringFromCGRect(self.view.frame));
// Result is (0, 0 , 768, 1024)
}
答案 0 :(得分:158)
有些事情你不明白。
首先,系统会在加载您的笔尖后立即向您发送viewDidLoad
。它还没有将视图添加到视图层次结构中。因此,它也没有根据设备的轮换调整视图大小。
其次,视图的框架位于其superview的坐标空间中。如果这是您的根视图,则其超级视图将是UIWindow
(一旦系统实际将您的视图添加到视图层次结构中)。 UIWindow
通过设置其子视图的变换来处理旋转。这意味着视图的框架不一定符合您的预期。
这里是纵向视图层次结构:
(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>>
这里是横向左方向的视图层次结构:
(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>>
请注意,在横向方向上,帧大小为748 x 1024,不 1024 x 748。
如果这是您的根视图,您可能想要查看的是视图的界限:
(lldb) p (CGRect)[0x9634ee0 bounds]
(CGRect) $3 = {
(CGPoint) origin = {
(CGFloat) x = 0
(CGFloat) y = 0
}
(CGSize) size = {
(CGFloat) width = 1024
(CGFloat) height = 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}} layoutSubviews
{{0, 0}, {1024, 748}} viewDidLayoutSubviews
{{0, 0}, {1024, 748}} willAnimateRotationToInterfaceOrientation:duration:
{{0, 0}, {1024, 748}} shouldAutorotateToInterfaceOrientation:
{{0, 0}, {1024, 748}} viewDidAppear:
您收到willRotateToInterfaceOrientation:duration:
后
viewWillLayoutSubviews
和viewWillLayoutSubviews
方法是iOS 5.0的新功能。
viewDidLayoutSubviews
消息将发送到视图,而不是视图控制器,因此如果要使用它,则需要创建自定义layoutSubviews
子类。
答案 1 :(得分:3)
这是一个干净的解决方案。
我遇到了同样的问题,我坚持在整个应用中使用frame
。我不想为根视图控制器做一个例外。我注意到根视图控制器的frame
显示了纵向尺寸,但所有子视图都具有正确的横向尺寸。
由于只有根视图控制器的行为不同,我们可以将标准的空白视图控制器设置为根视图控制器,并将自定义视图控制器添加到该控制器。 (以下代码。)
然后,您可以在自定义视图控制器中使用frame
。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.rootViewController = [[UIViewController alloc] init];
[self.window makeKeyAndVisible];
self.viewController = [[ViewController alloc] initWithNibName:nil bundle:nil];
[self.window.rootViewController addChildViewController:self.viewController];
[self.window.rootViewController.view addSubview:self.viewController.view];
return YES;
}
答案 2 :(得分:0)
这是另一种解决方案( Swift 4 ):
override func viewDidLoad() {
super.viewDidLoad()
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
基本上,这会强制视图控制器正确地布局其视图,并从那里可以获取所有子视图的正确框架。当制作过渡动画并且视图控制器使用自动布局和界面生成器时,这特别有用。
从我注意到的情况来看,初始帧似乎设置为您的界面生成器默认大小类设置的任何值。我通常使用iPhone XS尺寸类进行编辑,因此在viewDidLoad
中,无论您是否使用iPhone XR,视图的宽度始终为375。不过,这会在viewWillAppear
之前更正。
以上代码将纠正此问题,并允许您在将视图控制器呈现到屏幕之前为视图/子视图获取正确的帧。