NSWindow with round corners and shadow

后端 未结 11 1831
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-23 02:26

I\'m trying to crate a NSWindow without title bar (NSBorderlessWindowMask) with round corners and a shadow, similar to the below \"Welcome

相关标签:
11条回答
  • 2020-12-23 03:04

    There is a sample application on the Apple Developer Site that may help you with that. This sample demonstrates how to create windows with custom shapes, no title bar, and transparent content. It also shows how to change the shape of the window and recalculate the drop shadow around the window border.

    0 讨论(0)
  • 2020-12-23 03:07

    You have two options:

    1. Use the layer's shadow properties.
    2. Draw the shadow yourself in your drawRect routine. For this to work don't set the rounded corners but use an inset path to draw the rounded rectangle and its shadow.

    Code:

    @interface RoundedOuterShadowView : NSView {
    }
    
    @end
    
    @implementation RoundedOuterShadowView
    
    - (id)initWithFrame: (NSRect)frameRect
    {
        self = [super initWithFrame: frameRect];
        if (self != nil) {
        }
    
        return self;
    }
    
    // Shared objects.
    static NSShadow *borderShadow = nil;
    
    - (void)drawRect: (NSRect)rect
    {
        [NSGraphicsContext saveGraphicsState];
    
        // Initialize shared objects.
        if (borderShadow == nil) {
            borderShadow = [[NSShadow alloc] initWithColor: [NSColor colorWithDeviceWhite: 0 alpha: 0.5]
                                                    offset: NSMakeSize(1, -1)
                                                blurRadius: 5.0];
        }
    
        // Outer bounds with shadow.
        NSRect bounds = [self bounds];
        bounds.size.width -= 20;
        bounds.size.height -= 20;
        bounds.origin.x += 10;
        bounds.origin.y += 10;
    
        NSBezierPath *borderPath = [NSBezierPath bezierPathWithRoundedRect: bounds xRadius: 5 yRadius: 5];
        [borderShadow set];
        [[NSColor whiteColor] set];
        [borderPath fill];
    
        [NSGraphicsContext restoreGraphicsState];
    }
    
    @end
    
    0 讨论(0)
  • 2020-12-23 03:09

    Objective C example of @Eonil's answer:

    [window setBackgroundColor:[NSColor whiteColor]];
    [window setOpaque:NO];
    [window setStyleMask:NSResizableWindowMask | NSTitledWindowMask | NSFullSizeContentViewWindowMask];
    [window setMovableByWindowBackground:YES];
    [window setTitlebarAppearsTransparent:YES];
    [window setTitleVisibility:NSWindowTitleHidden];
    [window setShowsToolbarButton:NO];
    [window standardWindowButton:NSWindowFullScreenButton].hidden = YES;
    [window standardWindowButton:NSWindowMiniaturizeButton].hidden = YES;
    [window standardWindowButton:NSWindowCloseButton].hidden = YES;
    [window standardWindowButton:NSWindowZoomButton].hidden = YES;
    [window makeKeyWindow];
    
    0 讨论(0)
  • 2020-12-23 03:10

    I just created my own version of the Xcode splash screen for my application, including the recent files list view and all four corners are rounded:

    http://www.fizzypopstudios.com/splash.png

    The easiest way I found to do this was to create a window using the interface builder. I made the window 800x470 pixles, then I unchecked all the options except "Shadow" and "Restorable". This left me with a blank slate with which to create my splash screen.

    In the initWithContentRect:styleMask:backing:defer: method for the splash window I also set the following properties:

    self.opaque = NO
    self.backgroundColor = [NSColor clearColor]
    self.movableByWindowBackground = YES
    

    If you displayed the window at this point you would have no background, and the window shadow would automatically be set to be behind any non-transparent controls in the window.

    When I draw my window background I fill the left 500 pixels with light gray and the remaining 300 pixels on the right with white. If displayed the window would have no rounded corners at this point.

    I then use [NSColor clearColor] to notch squares out all 4 corners of the window (the size of the square is the radius of the rounded corner we will draw next). Then using Bezier Paths I draw in a rounded corner into the notches I just cut out.

    I tried to do this by creating a bezier path that when filled with [NSColor clearColor] would also result in a round corner, however, for some reason the path would not fill with clear, though it would fill with other colors.

    Now, if you render the window you will have rounded corners, however, if you drop a table view into the right side of the window the corners will become square again. The easy solution there is to set the NSScrollView to not draw a background, and then to set the nested NSTableView background to transparent.

    As we are drawing the background behind the table we don't really need the table or scroll view drawing a background, and this then preserves the rounded corners.

    If you have any other controls that go near the 4 corners just keep them indented enough to not be in the rounded area. An example of this is I have a button in the lower left of my window, however, since the button has transparency the rounded corner is not removed.

    One other consideration is you may want to provide canBecomeKeyWindow and canBecomeMainWindow methods in your window subclass to return YES as the default for these types of windows is NO.

    I hope this info helps you create your window, I saw your question a while ago and thought I would come back and let you know how I created my window in case it could help you! :)

    0 讨论(0)
  • 2020-12-23 03:11

    Update

    I realised old approach was not able to create precise round corner. So I updated example to make precise round corner.

            window1.backgroundColor             =   NSColor.whiteColor()
            window1.opaque                      =   false
            window1.styleMask                   =   NSResizableWindowMask
                                                |   NSTitledWindowMask
                                                |   NSFullSizeContentViewWindowMask
            window1.movableByWindowBackground   =   true
            window1.titlebarAppearsTransparent  =   true
            window1.titleVisibility             =   .Hidden
            window1.showsToolbarButton          =   false
            window1.standardWindowButton(NSWindowButton.FullScreenButton)?.hidden   =   true
            window1.standardWindowButton(NSWindowButton.MiniaturizeButton)?.hidden  =   true
            window1.standardWindowButton(NSWindowButton.CloseButton)?.hidden        =   true
            window1.standardWindowButton(NSWindowButton.ZoomButton)?.hidden         =   true
    
            window1.setFrame(CGRect(x: 400, y: 0, width: 400, height: 500), display: true)
            window1.makeKeyAndOrderFront(self)
    

    Here's full working example.


    Oudated

    Special treatment is not required at least in OS X 10.10.

    import Cocoa
    
    class ExampleApplicationController: NSObject, NSApplicationDelegate {
        class ExampleController {
    
            let window1 =   NSWindow()
            let view1   =   NSView()
    
            init(){
                window1.setFrame(CGRect(x: 400, y: 0, width: 400, height: 500), display: true)
                window1.contentView                 =   view1
    
                window1.backgroundColor             =   NSColor.clearColor()
                window1.opaque                      =   false
                window1.styleMask                   =   NSBorderlessWindowMask | NSResizableWindowMask
                window1.movableByWindowBackground   =   true
                window1.makeKeyAndOrderFront(self)
    
                view1.wantsLayer                =   true
                view1.layer!.cornerRadius       =   10
                view1.layer!.backgroundColor    =   NSColor.whiteColor().CGColor
    
                /// :ref:   http://stackoverflow.com/questions/19940019/nswindow-with-round-corners-and-shadow/27613308#21247949
                window1.invalidateShadow()  //  This manual invalidation is REQUIRED because shadow generation is an expensive operation.
            }
        }
    
        let example1    =   ExampleController()
    }
    

    You can download a working example from here.

    0 讨论(0)
提交回复
热议问题