【问题标题】:Reporting incorrect bounds in landscape Mode在横向模式下报告不正确的边界
【发布时间】:2023-03-22 19:58:01
【问题描述】:

我在 iPad 应用程序中遇到横向模式问题。

我创建了一个非常小的新项目来显示我的问题 我将 pList 中的 UIInterfaceOrientation 设置为 UIInterfaceOrientationLandscapeRight

应用内委托

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    [self.window makeKeyAndVisible];
    MyController *myController = [[MyController alloc] init];
    [self.window addSubview:myController.view];

    return YES;
}

在我的控制器中

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"Bounds Height:%f %f", self.view.bounds.size.height, self.view.bounds.size.width);
}

我也试过把它放在 viewDidLoad 中,结果相同

如果我在横向手持设备的同时启动应用程序,NSLog 输出

Bounds Height: 1004.000000 Bounds Width: 768.000000

我需要做什么才能获得正确的结果? 我是这个 iOS 编程的新手,我想做的只是将 UISlider 锚定到屏幕底部,但是当我得到不正确的坐标时,我不确定该怎么做。

【问题讨论】:

  • 您是专门寻找绑定的吗? bound 和 frame 是不同的。 stackoverflow.com/questions/1210047/…
  • 同时使用边界或框架给了我相同的结果。
  • 这不是一个错误,而是一个特性。 Bounds 总是会给你同样的结果。因为您知道您是处于横向还是纵向模式,您仍然可以使用边界进行任何计算。这很令人困惑,但我认为它应该是这样的。
  • 你实现了通常的 shouldAutorotate 方法了吗?横向启动时,状态栏是否出现在屏幕顶部?
  • bresc,你错了。看我的回答。你的意思是“框架总是一样的”吗?

标签: iphone objective-c cocoa-touch uikit


【解决方案1】:

您过早地检查框架和边界大小。

相反,请在旋转后检查它们:

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    NSLog(@"Bounds %@", NSStringFromCGRect(self.view.bounds));
    NSLog(@"Frame %@", NSStringFromCGRect(self.view.frame));
}

(注意我使用了NSStringFromCGRect——很方便!)

这会产生输出:

Bounds {{0, 0}, {1024, 748}}
Frame {{0, 0}, {748, 1024}}

所以在这个输出中,框架是“错误的”,但边界是你所期望的。事实上,框架实际上并没有错,这就是框架 -> 边界计算发生的方式。所以你需要访问边界。

也可以看看Do I have the right understanding of frames and bounds in UIKit?

注意viewDidAppear 比你想象的更早被调用。根据 Apple 文档:“viewDidAppear 通知视图控制器其视图已添加到窗口中。”换句话说,它可以在应用任何旋转之前发生。

【讨论】:

  • 你的头像似乎符合主题。
【解决方案2】:

我认为这里没有回答原始问题,因为我遇到了同样的问题。

这里的关键是,如果模拟器/设备处于横向模式,然后您启动程序,self.view.(frame or bounds) 会检索纵向高度和宽度。如果您的程序已经在运行,然后您旋转它会给出正确的值。这仅在设备以横向启动且未旋转时发生。

有没有其他人找到解决方案或知道我做错了什么?请和谢谢。

可能的解决方案

我之前一直从 viewDidLoad 方法调用我的方法。事实证明,视图仍在转换。通过从 viewDidAppear 调用我的函数来获得更好的运气,该函数在所有操作完成后调用。

希望对您有所帮助。

【讨论】:

  • 谢谢瑞秋!我花了一个小时试图弄清楚我做错了什么。然后我偶然发现了你的答案,现在一切都很好。你救了我!
  • ofc 就是这么简单。谢谢!
  • ViewWillAppear 而不是 ViewDidLoad 为我做了。很棒的东西。
  • 是的,我是另一个犯了这个错误的人。感谢您的提示!
  • 试试viewDidLayoutSubviews,它在viewWillAppear之后和viewDidAppear之前调用
【解决方案3】:

我遇到了同样的问题并像这样破解了它:

- (CGSize)getRotatedViewSize
{
    BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation);

    float max = MAX(self.view.bounds.size.width, self.view.bounds.size.height);
    float min = MIN(self.view.bounds.size.width, self.view.bounds.size.height);

    return (isPortrait ? 
            CGSizeMake(min, max) : 
            CGSizeMake(max, min));            
}

【讨论】:

    【解决方案4】:

    viewWillAppear(根据 Paul Hegarty 的 CS193p 讲座)用于几何相关的初始化。由于 viewDidAppear 遵循 viewWillAppear ,因此边界在这里也是正确的是有道理的。视图边界尚未在 viewDidLoad 中设置。

    【讨论】:

      【解决方案5】:

      我创建了一个小项目来测试框架和边界,因为我遇到了同样的问题。 事实上,检查 viewDidLoad 的边界解决了我的问题。

      我不断挖掘,发现 viewWillLayoutSubviews 方法的边界也是正确的。所以我猜想在项目中布局视图的最“正确”方式是:

      1. 在 viewDidLoad 或 loadView 上分配并实例化它们,并使用您认为当时正确的帧。

      2. 在 viewWillLayoutSubviews 上重新布局您创建的视图,以便它们在视图实际出现时位于正确的位置。

      【讨论】:

        【解决方案6】:

        除了viewDidAppear:,请确保使用_window.rootViewController 而不是[_window addSubview:_rootViewController.view]。这也解决了我在 iOS6 上的问题。

        AppDelegate.m:

        - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
          _window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
          _rootViewController = [[MyRootViewController alloc] init];
          _window.rootViewController = _rootViewController;
          [_window makeKeyAndVisible];
          return YES;
        }
        

        MyRootViewController.m:

        - (void)viewDidAppear:(BOOL)animated {
          [super viewDidAppear:animated];
          NSLog(@"bounds: %@", NSStringFromCGRect(self.view.bounds));
          UIView *myView = [[UIView alloc] initWithFrame:self.view.bounds];
          [self.view addSubview:myView];
        }
        

        【讨论】:

          【解决方案7】:

          已接受答案中的一个 cmets 包含对我来说问题的解决方案。

          您可以在 UIViewController 上覆盖一个名为“viewDidLayoutSubviews”的方法,我利用它并从那里调整了我的包含视图。

          由于它在“viewWillAppear”之后和“viewDidAppear”之前调用,因此您对子视图所做的更改会按预期显示,没有故障。

          【讨论】:

          • 如果您需要它们在视图出现时正确显示,我认为这是设置任何子视图的正确位置。例如在两个控制器之间的过渡动​​画中。
          【解决方案8】:

          我也遇到过同样的事情。

          你必须用勺子喂 iOS 并将这行代码放在这里,否则它会给你错误的答案。

          -(void) viewWillAppear:(BOOL)animated
          {
            [super viewWillAppear:animated];
            //required because device orientation will give you the wrong values
            [UIViewController attemptRotationToDeviceOrientation];
            int orientation = [[UIDevice currentDevice] orientation];
            BOOL isPortrait = false;
          
            if (orientation == 3 || orientation == 4)
              isPortrait = false;
            else
              isPortrait = true;
            NSLog(@"is portrait %i ?", isPortrait);
          }
          

          【讨论】:

            【解决方案9】:
            UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
            CGRect r = self.view.frame;
            CGFloat width = r.size.width;
            CGFloat height = r.size.height;
            r.size.height = (UIInterfaceOrientationIsLandscape(orientation)) ? MIN(width, height): MAX(width, height);
            r.size.width  = (UIInterfaceOrientationIsLandscape(orientation)) ? MAX(width, height): MIN(width, height);
            self.view.frame = r;
            

            【讨论】:

            • 你会把它放在哪里?
            猜你喜欢
            • 1970-01-01
            • 2017-09-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多