Search code examples
objective-ccocoacore-animationnsviewdropshadow

NSView Drop Shadow Using setShadow:


I'm attempting to make a drop shadow for a custom NSView subclass.

So far, I've managed:

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        NSShadow *dropShadow = [[NSShadow alloc] init];
        [dropShadow setShadowColor: [NSColor redColor]];

        [self setWantsLayer: YES];
        [self setShadow: dropShadow];
    }

    return self;
}

- (void)drawRect:(NSRect)dirtyRect
{
    [[NSColor blueColor] setFill];
    NSRectFill(dirtyRect);

    [super drawRect: dirtyRect];
}

which only renders a blue square (i.e. no shadow).

Am I setting up the drop shadow in the right place? Am I meeting all of the necessary requirements for the use of setShadow:?


Solution

  • A few notes before answering the question:

    • You don't need to call super's implementation of drawRect: on a vanilla NSView. The default implementation does nothing.
    • You should be using [self bounds] as the fill rectangle, not dirtyRect. The dirtyRect parameter is used to indicate the part of the view that needs drawing and is used for drawing optimisation only.
    • You are leaking the dropShadow object. You should either call autorelease on it after creation or call release on it after calling setShadow:.

    The reason that the shadow isn't displaying are twofold. Firstly, in order for layer-backed views to display a shadow, the view's superview must also be layer-backed.

    Secondly, you're setting the shadow's color but not its other parameters:

    - (id)initWithFrame:(NSRect)frame
    {
        self = [super initWithFrame:frame];
        if (self)
        {
            NSShadow *dropShadow = [[NSShadow alloc] init];
            [dropShadow setShadowColor:[NSColor redColor]];
            [dropShadow setShadowOffset:NSMakeSize(0, -10.0)];
            [dropShadow setShadowBlurRadius:10.0];
    
            [self setWantsLayer: YES];
            [self setShadow: dropShadow];
    
            [dropShadow release];
        }
    
        return self;
    }