如何在 NSWindow 全屏模式下显示模式 sheet 而无需视觉移动主机 window?

How can I display a modal sheet in NSWindow fullscreen mode without visually shifting the host window?

Objective-C 桌面 Cocoa 应用程序。该应用程序是一个高度特定的边缘案例(具有一键式界面的独立信息亭)。我首先提到这一点是为了避免 HIG 讲座。 ;)

我正在使用模态 sheet 视图在常用内容之上显示 PDF 文档。代码很简单:

[docViewerHostWindow beginSheet:docViewer completionHandler:nil];

DocViewerHostWindow 是作为调用 sheet 的 NSView 的父级访问的 NSWindow。如果重要的话,"docViewer" 是包含 PDFView 的 NSWindow 的子类。

当应用程序在 window 中 运行 时,一切正常。当应用程序是 运行 全屏时,一切都像宣传的那样工作,但有一个视觉故障:模型后面的整个内容向右移动,直到 sheet 被关闭。看起来这是故意的(并且是动画的)但我无法弄清楚它来自哪里或如何禁用它。

我是这样进入全屏的:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO],NSFullScreenModeAllScreens,nil];

[self enterFullScreenMode:[NSScreen mainScreen] withOptions:options];

这个基本的 NSLog 说明了问题:

NSLog(@"Before: %f,%f",docViewerHostWindow.frame.origin.x,docViewerHostWindow.frame.origin.y);

[docViewerHostWindow beginSheet:docViewer completionHandler:nil];

NSLog(@"After: %f,%f",docViewerHostWindow.frame.origin.x,docViewerHostWindow.frame.origin.y);

**Log when running windowed (same origin before and after) **
2015-08-09 22:52:46.641 Before: 311.000000,491.000000
2015-08-09 22:52:47.050 After: 311.000000,491.000000

**Log when running fullscreen (origin shifts in fullscreen) **
2015-08-09 22:52:46.641 Before: 0.000000,0.000000
2015-08-09 22:52:47.050 After: 80.000000,-23.000000

我曾尝试在打开 sheet 之前和之后强制显示 window 的来源,但这没有帮助。我什至不确定去哪里看 - 是否有任何关于造成这种情况的原因和原因的线索?


更新: 需要说明的是,我不是在谈论 sheet 本身的默认动画(如 this question 中所述)而是这是一些东西主机 window 会发生这种情况,但仅限于全屏。

这个问题显然与 window 避开 Dock 有关。

我认为这也与您在全屏模式下放置视图而不是 window 有关。当您这样做时,视图有点偏离其正常 window。但是,当您在视图的 window 上开始一个 sheet 时,可以这么说,您将把它带回到图片中。 (您可能会检查视图的 window 属性 是否实际上与进入全屏模式之前相同 window。如果不是,那么您真的没有必要附加 sheet 到它。)

我建议您使用 window 的无边框 window,定位为覆盖屏幕,在 NSStatusWindowLevel + 1 的 window 级别。这是 Apple 的 OpenGL Programming Guide for Mac: Drawing to the Full Screen 中推荐的技术(不可否认,这与您正在使用的环境有些不同)。所以,你不会使用 -[NSView enterFullScreenMode:withOptions:]。如果你想为 kiosk 模式类型的行为设置应用程序的 presentationOptions,你也可以这样做。

看到的效果是应用程序移出了(不可见的)停靠栏和菜单栏(感谢@KenThomases,他的评论帮助解决了这个问题)。除了上面接受的答案外,我还找到了另一个解决方案:

A​​pple 提供了一些 kiosk mode tricks 在这里很有用,特别注意他们关于通过向 awakeFromNib 添加代码来隐藏菜单栏和停靠栏的示例。

但是,这在非信息亭 ap 中不太理想,我们希望仅在全屏模式下具有信息亭选项。幸运的是,这可以通过将选项传递给 enterFullScreenMode:withOptions: 来实现。当我们 exitFullScreenMode:withOptions

时,常规演示模式选项将恢复

文档有点单薄,但这确实有效:

NSApplicationPresentationOptions kioskOptions = NSApplicationPresentationHideDock + NSApplicationPresentationHideMenuBar;

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                         [NSNumber numberWithBool:NO],NSFullScreenModeAllScreens,
                         [NSNumber numberWithInteger:kioskOptions],NSFullScreenModeApplicationPresentationOptions, nil];

[self enterFullScreenMode:[NSScreen mainscreen] withOptions:options];