To use;
- Simply download
SnappyWindow.swift
from this gist and add it to your Xcode project - Instantiate a window with
SnappyWindow()
import Cocoa | |
import SwiftUI | |
@main | |
class AppDelegate: NSObject, NSApplicationDelegate { | |
var window: SnappyWindow! | |
func applicationDidFinishLaunching(_ aNotification: Notification) { | |
let contentView = ContentView() | |
// Create the window and set the content view. | |
window = SnappyWindow( | |
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300), | |
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], | |
backing: .buffered, defer: false) | |
window.isReleasedWhenClosed = false | |
window.center() | |
window.isMovableByWindowBackground = true | |
window.contentView = NSHostingView(rootView: contentView) | |
window.makeKeyAndOrderFront(nil) | |
} | |
func applicationWillTerminate(_ aNotification: Notification) { | |
// Insert code here to tear down your application | |
} | |
} |
// | |
// SnappyWindow.swift | |
// A NSWindow that snaps to corners | |
// | |
// Created by Alasdair Monk on 03/02/2021. | |
// | |
import Foundation | |
import Cocoa | |
/// An NSWindow with the super power to snap to corners of the screen | |
class SnappyWindow: NSWindow, NSWindowDelegate { | |
enum SnapPosition: Int { | |
case bottomLeft = 1 | |
case bottomRight = 4 | |
case topLeft = 2 | |
case topRight = 3 | |
} | |
/// Padding from edge of screen | |
let padding: CGFloat = 10 | |
/// The latest position the window was snapped to | |
var snapPosition: SnapPosition? | |
private var hasBeenDragged: Bool = false | |
override func mouseDragged(with event: NSEvent) { | |
print("Drag") | |
self.hasBeenDragged = true | |
} | |
override func mouseUp(with event: NSEvent) { | |
print("Mouse up") | |
if self.hasBeenDragged { | |
let mouseY = NSEvent.mouseLocation.y | |
let mouseX = NSEvent.mouseLocation.x | |
if mouseY > (NSScreen.main?.frame.height)! / 2 && mouseX < (NSScreen.main?.frame.width)! / 2 { | |
self.snapTo(position: .topLeft) | |
self.snapPosition = .topLeft | |
} | |
if mouseY <= (NSScreen.main?.frame.height)! / 2 && mouseX < (NSScreen.main?.frame.width)! / 2 { | |
self.snapTo(position: .bottomLeft) | |
self.snapPosition = .bottomLeft | |
} | |
if mouseY > (NSScreen.main?.frame.height)! / 2 && mouseX >= (NSScreen.main?.frame.width)! / 2 { | |
self.snapTo(position: .topRight) | |
self.snapPosition = .topRight | |
} | |
if mouseY <= (NSScreen.main?.frame.height)! / 2 && mouseX >= (NSScreen.main?.frame.width)! / 2 { | |
self.snapTo(position: .bottomRight) | |
self.snapPosition = .bottomRight | |
} | |
self.hasBeenDragged = false | |
} | |
} | |
func snapTo(position: SnapPosition) { | |
switch position { | |
case .bottomLeft: | |
self.animator().setFrame(NSRect(x: padding, y: padding + padding, width: self.frame.width, height: self.frame.height), display: false, animate: true) | |
case .topLeft: | |
let position = (NSScreen.main?.frame.height)! - self.frame.height - padding | |
self.animator().setFrame(NSRect(x: padding, y: position, width: self.frame.width, height: self.frame.height), display: false, animate: true) | |
case .bottomRight: | |
self.animator().setFrame(NSRect(x: (NSScreen.main?.frame.width)! - self.frame.width - padding, y: padding + padding, width: self.frame.width, height: self.frame.height), display: false, animate: true) | |
case .topRight: | |
self.animator().setFrame(NSRect(x: (NSScreen.main?.frame.width)! - self.frame.width - padding, y: (NSScreen.main?.frame.height)! - self.frame.height - padding, width: self.frame.width, height: self.frame.height), display: false, animate: true) | |
} | |
} | |
} |