【问题标题】:NSWindow Shadow OutlineNSWindow 阴影轮廓
【发布时间】:2026-02-08 13:05:02
【问题描述】:

我正在通过为窗口设置自定义内容视图来绘制自定义窗口。当我绘制自定义视图时,我会给它圆角和漂亮的轮廓以模仿适当的窗口。

但是,我在窗口周围看到另一个 1 px 的轮廓,它偏离了角落的边缘。我发现如果我关闭阴影它会消失,但显然因为它想像窗户一样我需要阴影。这就是我对 1px 轮廓的意思:

我怎样才能防止这种情况发生?


编辑

绘制自定义窗口内容视图的代码:

    NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5];

    NSGradient* aGradient = [[[NSGradient alloc] initWithColorsAndLocations:
                              [NSColor colorWithDeviceRed:0.5569 green:0.5137 blue:0.4588 alpha:1.0000], 0.0,
                              [NSColor colorWithDeviceRed:0.5569 green:0.5137 blue:0.4588 alpha:1.0000], 1.0,
                              nil] autorelease];

    [aGradient drawInBezierPath:path angle:90];

    [path setLineWidth:4];
    [[NSColor colorWithDeviceRed:0.4235 green:0.3922 blue:0.3451 alpha:0.9000] setStroke];
    [path strokeInside];

    [path setLineWidth:3];
    [[NSColor colorWithDeviceRed:0.8431 green:0.8314 blue:0.8078 alpha:1.0000] setStroke];
    [path strokeInside];

    [path setLineWidth:1];
    [[NSColor colorWithDeviceRed:0.4235 green:0.3922 blue:0.3451 alpha:0.9000] setStroke];
    [path strokeInside];

【问题讨论】:

    标签: objective-c cocoa macos nswindow shadow


    【解决方案1】:

    不要问我是怎么得到这个的,但这会解决你的问题。

    使用以下内容为NSWindow 定义一个类别:

    @implementation NSWindow(NoShadowRim)
    
    - (id)_shadowRimInfo {
      return @{
        @"kCUIMeasureWindowFrameRimDensity": [NSNumber numberWithInt:0]
      };
    }
    
    @end
    

    免责声明:这会覆盖NSWindow 的内部方法,因此使用它需要您自担风险。它可能会因任何 OS X 更新而中断。

    【讨论】:

    • 回顾这个旧项目,我不再看到 OS X Yosemite 上出现完全相同的问题,因此很遗憾无法确认这是否解决了原始问题。然而,我可以确认这确实会影响阴影边缘,它会完全移除边缘。谢谢!
    【解决方案2】:

    您需要通过发送-invalidateShadow 告诉窗口重新计算其阴影。

    【讨论】:

    • 在这种情况下,我认为您必须向我们展示一些代码。
    【解决方案3】:

    试试:

    [[self window] display];
    [[self window] setHasShadow:NO];
    [[self window] setHasShadow:YES];
    

    【讨论】:

    • 我应该把这段代码放在哪里?如果我把它放在drawRect: 中,它只会创建一个无限循环,因为它会不断调用display
    • 是的,把它放在drawRect之外。每当我更新我的 customView 时我都会使用它,但我猜想在 awakeFromNib 或 windowDidLoad 里面应该可以工作。
    • 试过了,很遗憾还是没有解决问题。
    【解决方案4】:

    自动绘制窗口区域轮廓线。我有一个窗口,这条线在底部圆角周围准确运行。您必须将窗口设置为不透明,并将背景颜色设置为透明:

      [self setOpaque:NO];
      [self setBackgroundColor:[NSColor clearColor]];
    

    contentView 中的某处 -drawRect:你这样做

      [NSGraphicsContext saveGraphicsState];
      [pathWithBottomRoundedCorner addClip];
      // your drawing here...
      [NSGraphicsContext restoreGraphicsState];
    

    应该可以的。

    【讨论】:

    • 不,仍然没有运气。这是我正在使用的代码 gist.github.com/1082923 加上我的 NSWindow 子类中的第一个代码块。
    • 对不起,我想我读错了你的问题。你确实有两次大纲,想摆脱系统一次吗? not 在您自己的 drawRect: 中绘制轮廓可能不是一个简单的解决方案吗?配置窗口阴影时,看起来总是在剪切路径周围添加轮廓。
    • 我需要画一个不同的轮廓,因为它需要不同的颜色才能看起来不错。即使没有我画出轮廓,它看起来仍然不正确,cl.ly/8Tq8。有没有办法关闭系统大纲?
    • 对不起,我不能告诉你。我看了很多窗户,包括时髦的窗户,但那些有阴影的窗户周围也有这个轮廓/笔触/轮廓线。
    【解决方案5】:

    据我了解,阴影是由 Windows 服务器绘制的。当您绘制带有圆角或其他非矩形形状的自定义 NSWindow 时,窗口服务器不会计算那些透明像素并且不会在它们下方投下阴影。

    我开发了一些技巧来避免这种行为。只需在路径下添加额外的阴影,如下所示:

    NSShadow *headShadow = [[NSShadow alloc] init];
    [headShadow setShadowColor:[NSColor colorWithSRGBRed:0.0 
                                                   green:0.0 
                                                    blue:0.0 
                                                   alpha:0.16]];
    [headShadow setShadowBlurRadius:0.0f];
    [headShadow setShadowOffset:NSMakeSize(0.0f, 0.0f)];
    [headShadow set];
    

    理想情况下,我 fink shadow 必须等于窗口服务器。

    【讨论】:

    • 我已将该代码放在问题之前,它没有任何区别。但是我不确定我是否按照您所说的正确进行。
    • 尝试在你之前添加这样的代码:NSShadow *shadow = [[NSShadow alloc] init]; [shadow setShadowColor:[NSColor colorWithSRGBRed:1.0 green:0.0 blue:0.0 alpha:1.0]]; [shadow setShadowBlurRadius:0.0f]; [shadow setShadowOffset:NSMakeSize(0.0, 0.0)]; [shadow set]; 填充笔画之间似乎有一些透明像素。