为什么我无法在 iPad 上填充外部屏幕(但不是在模拟器中)?

Why am I having trouble filling an external screen on iPad (but not in simulator)?

我能够检测到何时检测到屏幕,将其与适当的 windowScene 相关联并向其添加视图。由于this SO question:

class ExternalViewController: UIViewController {
  override func viewDidLoad() {
    view.backgroundColor = .cyan
    print("external frame \(view.frame.width)x\(view.frame.height)")
  }
}
class ViewController: UIViewController {
  var additionalWindows: [UIWindow] = []
  override func viewDidLoad() {
    //nb, Apple documentation seems out of date.
    //
    NotificationCenter.default.addObserver(forName: UIScreen.didConnectNotification, object: nil, queue: nil) { [weak self] notification in
      guard let self = self else {return}

      guard let newScreen = notification.object as? UIScreen else {return}
      // Give the system time to update the connected scenes
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
        // Find matching UIWindowScene
        let matchingWindowScene = UIApplication.shared.connectedScenes.first {
        guard let windowScene = [=11=] as? UIWindowScene else { return false }
        return windowScene.screen == newScreen
      } as? UIWindowScene

        guard let connectedWindowScene = matchingWindowScene else {
          NSLog("--- Connected scene was not found ---")
          return
          //fatalError("Connected scene was not found") // You might want to retry here after some time
        }
        let screenDimensions = newScreen.bounds

        let newWindow = UIWindow(frame: screenDimensions)
        NSLog("newWindow \(screenDimensions.width)x\(screenDimensions.height)")
        newWindow.windowScene = connectedWindowScene

        let vc = ExternalViewController()
        vc.mainVC = self

        newWindow.rootViewController = vc
        newWindow.isHidden = false
        self.additionalWindows.append(newWindow)
      }
    }
  }
}

当我在 iOS 模拟器中执行此操作时,我看到我的图形按预期填满了屏幕,但是当 运行 在我的实际设备上时,它的四周都出现了明显的黑色边框.

请注意,这不是默认显示镜像行为中常见的边框 - 16:9 宽高比得以保留,我确实看到了预期的不同图形,(我的示例代码中的纯青色,通常我正在做一些金属渲染,其中有一些超出此处范围的轻微异常,但如果我深入研究它可能会导致一些不同的线索)。

打印消息报告了预期的 1920x1080 尺寸。我对 UIKit 不是很了解,也没有做太多积极的 Apple 开发(我正在清理这里的几个旧项目,希望能够在附近的演出中使用它们来投影视觉效果未来),所以我不知道是否还有其他与我可能遗漏的大小限制等有关的东西,但即使如此,也很难看出为什么它在模拟器中的行为会有所不同。

我从应用商店安装的其他应用确实会在外部显示器上显示全屏图形 - Netflix 显示全屏视频如您所料,概念画板显示的文档表示与您在设备上看到的不同。

因此,在本例中,问题与 Overscan Compensation 有关。感谢 Discord 上的 Jerrot 为我指明了正确的方向。

在我的应用程序上下文中,在连接通知委托中添加 newScreen.overscanCompensation = .none 就足够了(实际上,在那之后延迟几毫秒的部分 - 如果直接应用它不起作用在连接通知中)。在上面链接的问题中,进一步讨论了在不同上下文中可能很重要的其他方面。

这是我的 ViewController 修改以达到预期的结果:

class ViewController: UIViewController {
  var additionalWindows: [UIWindow] = []
  override func viewDidLoad() {
    //nb, Apple documentation seems out of date.
    //
    NotificationCenter.default.addObserver(forName: UIScreen.didConnectNotification, object: nil, queue: nil) { [weak self] notification in
      guard let self = self else {return}

      guard let newScreen = notification.object as? UIScreen else {return}
      // Give the system time to update the connected scenes
      DispatchQueue.main.asyncAfter(deadline: .now() + 0.05) {
        // Find matching UIWindowScene
        let matchingWindowScene = UIApplication.shared.connectedScenes.first {
        guard let windowScene = [=10=] as? UIWindowScene else { return false }
        return windowScene.screen == newScreen
      } as? UIWindowScene

        guard let connectedWindowScene = matchingWindowScene else {
          NSLog("--- Connected scene was not found ---")
          return
          //fatalError("Connected scene was not found") // You might want to retry here after some time
        }
        let screenDimensions = newScreen.bounds
      ////// new code here --->  
        newScreen.overscanCompensation = .none
      //////
        let newWindow = UIWindow(frame: screenDimensions)
        NSLog("newWindow \(screenDimensions.width)x\(screenDimensions.height)")
        newWindow.windowScene = connectedWindowScene

        let vc = ExternalViewController()
        vc.mainVC = self

        newWindow.rootViewController = vc
        newWindow.isHidden = false
        self.additionalWindows.append(newWindow)
      }
    }
  }
}

在这个时代,我觉得默认启用过扫描补偿很奇怪。