Day 53: Transparent windows
A question that seems to come up online from time to time is how to create a window in a special shape; rounded corners or with arrows sticking out on a side much like those popovers on the iPad. I use something similar in Sketch and here’s the basic outline of how to do it:
You start by subclassing NSWindow and overriding the initWith… method. You can also create it in code of course but that means you can’t use IB, up to you. You’ll also see that when we subclass we can do some neat things.
- (id)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)aStyle
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)flag
{
self = [super initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
if (self) {
[self setAlphaValue:1.0];
[self setOpaque:NO];
[self setHasShadow:YES];
}
return self;
}
I’ts important to override the following method to return YES if that’s important to you because by default borderless windows can’t become key:
- (BOOL)canBecomeKeyWindow
{
return YES;
}
Borderless windows also can’t be moved by the mouse since there’s no titlebar. Do create this behaviour yourself override mouseDown and mouseDragged to do something along the lines of this:
- (void)mouseDown:(NSEvent *)theEvent
{
initialLocation = [theEvent locationInWindow];
}
- (void)mouseDragged:(NSEvent *)theEvent
{
NSRect screenFrame = [[NSScreen mainScreen] visibleFrame];
NSRect windowFrame = [self frame];
NSPoint newOrigin = windowFrame.origin;
NSPoint currentLocation = [theEvent locationInWindow];
newOrigin.x += (currentLocation.x - initialLocation.x);
newOrigin.y += (currentLocation.y - initialLocation.y);
[self setFrameOrigin:newOrigin];
}
Now you’ll have an empty window. To provide the content for this window we provide our own contentView for the window which will do the actual drawing. Just override -drawRect: and you’re done. One issue you might get is that when you try draw the view in a different way, the window will have cached the shadow of the old view so keep that in mind. I believe resizing the window slightly will do the trick.