使用圆角的自定义NSWindow,可以裁剪子视图

8
我正试图创建自定义的NSWindow,我已经创建了一个带有正确无边框窗口遮罩的窗口,这很有效。我提供了自己的内容视图,这很好。但是我要做的是绘制具有圆角的、同时裁剪子视图到那些角落的内容,这可能吗?
在我的内容视图中,我可以重写drawRect:并绘制具有圆角的路径,但当我向其中添加子视图时,它们不被裁剪。
我可以将我的内容视图设置为层支持并给它一个圆角半径(masksToBounds设置为YES),但当我添加子视图时,它们仍然没有被我的圆角裁剪。
有没有办法做到这一点?或者有一种方法可以绘制没有标题栏的NSWindow,并完全控制绘图,同时保持圆角和裁剪效果?
3个回答

13

我所做的是提供一个自定义子类的NSWindow:

@implementation ELGRoundWindow

- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
    self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag];

    if ( self )
    {
        [self setStyleMask:NSBorderlessWindowMask];
        [self setOpaque:NO];
        [self setBackgroundColor:[NSColor clearColor]];
    }

    return self;
}


- (void) setContentView:(NSView *)aView
{
    aView.wantsLayer            = YES;
    aView.layer.frame           = aView.frame;
    aView.layer.cornerRadius    = 20.0;
    aView.layer.masksToBounds   = YES;


    [super setContentView:aView];

}

@end

然后在IB中,我将我的内容视图的类更改为ELGRoundView:

@implementation ELGRoundView

- (void)drawRect:(NSRect)dirtyRect
{
    [[NSColor colorWithCalibratedRed:0.0 green:0.5 blue:1 alpha:1] set];
    NSRectFill(dirtyRect);
}

@end

我在内容视图中放置了另一个正方形子视图,代码如下:

@implementation ELGSquareView

- (void)drawRect:(NSRect)dirtyRect
{
    [[NSColor colorWithCalibratedRed:0.0 green:0 blue:1 alpha:1] set];
    NSRectFill(dirtyRect);
}

@end

我得到的结果是:

我最终得到了:

裁剪子视图的圆形窗口


其他读者应该注意,OpenGL 应用程序应该只使用一个 glDrawArrays() 命令来绘制整个场景,否则会导致图层出现奇怪的结果。更进一步地,在这个问题的范围内,对于 OS X 风格的圆角,请使用 4.5-5.0 的角度。如果您想要,您也可以保留正常的标题栏,而不会让它看起来太不同。 - Justin
4
@ericgorr 你有什么办法让这个东西有阴影吗? - ThE uSeFuL

5

@ericgorr所建议的是正确的。此外,如果您想要窗口可移动和可调整大小,请将NSWindow的init更改为以下内容:

- (id)initWithContentRect:(NSRect)contentRect
                 styleMask:(NSUInteger)aStyle
                   backing:(NSBackingStoreType)bufferingType
                     defer:(BOOL)flag
{
    self = [super initWithContentRect:contentRect
                            styleMask:aStyle
                              backing:bufferingType
                                defer:flag];
    if (self) {            
        [self setOpaque:NO];
        [self setBackgroundColor:[NSColor clearColor]];
        [self setMovableByWindowBackground:YES];
        [self setStyleMask:NSResizableWindowMask];
    }
    return self;
}

如需进一步自定义,请参考苹果示例代码http://developer.apple.com/library/mac/#samplecode/RoundTransparentWindow/Introduction/Intro.html


1

子类化是最灵活的方式。 如果您不想使用子类化,请使用此代码。

// unfortunately the window can't be moved
// but this is just an alert type window, so i don't care
//
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];

NSView*  contentView = window.contentView;

contentView.wantsLayer = YES;
contentView.layer.backgroundColor = [NSColor windowBackgroundColor].CGColor;
contentView.layer.masksToBounds = YES;
contentView.layer.cornerRadius = 16.0;

[window makeKeyAndOrderFront:self];
[window center];

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