NSView或NSWindow中的漏洞

14

是否可以切割NSWindow或NSView的某些部分,使它们变成透明的? 我有一个带有NSView的NSWindow,我想要:

A)在NSWindow中打一个洞,以便能够透过它看到外面

B)将我的NSWindow背景设置为透明色,然后在上面放置一个NSView,并将NSView的某个部分的不透明度设置为透明以便能够透过去看到桌面。

这是我试图创建的效果:

enter image description here


1个回答

26

是的,这是可能的,而且实际上并不难。

在您的窗口子类中,您需要将窗口背景颜色设置为透明。

self.backgroundColor = NSColor.clearColor;

告诉合成引擎您窗口的某些部分是透明的,当窗口移动时需要重新绘制

[self setOpaque:NO];

在早期版本的macOS中,设置背景色并不是必要的,而且许多答案仍然没有提到这一事实。但我已经验证,至少在macOS 10.11及以后版本中是必要的。

在您的NSView子类中,您必须使用您选择的颜色来渲染新的背景(否则窗口完全透明,只会显示标题栏),然后用

NSRectFillUsingOperation(NSMakeRect(50, 50, 100, 100), NSCompositingOperationClear);

这样做可以得到期望的效果,并且在Mojave的暗模式下也适用。

在暗模式下有孔洞的窗口

完整代码:

@interface MyWindow : NSWindow
    - (id)initWithContentRect:(NSRect)contentRect styleMask:( unsigned    int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag;
@end

@implementation MyWindow
   - (id)initWithContentRect:(NSRect)contentRect styleMask:( unsigned   int)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
        self = [super initWithContentRect:contentRect styleMask : aStyle backing :bufferingType defer:flag ];
        if (self)
        {
            self.backgroundColor = NSColor.clearColor;
            [self setOpaque:NO];
            [self setHasShadow:NO];
        }
        return self;
}
@end

@interface MyView : NSView
- (void)drawRect:(NSRect)rect;
@end

@implementation MyView
- (void)drawRect:(NSRect)rect
{
    [[NSColor windowBackgroundColor] set];
    NSRectFill(self.bounds);
    NSRectFillUsingOperation(NSMakeRect(50, 50, 100, 100), NSCompositingOperationClear);
}
@end

如果我想保留第一个视图并添加第二个视图或子视图,我仍然可以使用NSCompositeClear吗?是否可能透过视图和窗口看到后面的内容? - Grant Wilkinson
1
此截图所示,父视图绘制代码中的NSCompositeClear不会穿透子视图进行绘制。然而,在子视图的绘制代码中使用NSCompositeClear将会穿透其父视图进行绘制。 - spudwaffle
1
答案中缺少什么?1.窗口背景颜色应为0.01 alpha值,以便获取事件。2.自定义子视图,您可以填充颜色,然后使用组合操作清除您想要透明的矩形。 - Marek H
我在 MyWindow 上错过了 hasShadow。这就是解决我的所有问题的方法。(当时我并不关心阴影。) 看起来 MyView.drawRect 只是在第一次绘制时穿过。当我在其他地方重新绘制孔时,后备窗口似乎没有更新孔。切换可以解决问题。谢谢! - waggles
1
这是一个很好的答案。唯一的问题是在暗模式下窗口标题栏的表现不正确。它有一个NSVisualEffectView,只有在其后面有窗口背景时才看起来正确。如果您在标题栏位于亮点上时激活应用程序,则它会记住并带着它四处走动。我没有解决方案,但我认为其他人应该知道。 - George

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接