Skip to content

Instantly share code, notes, and snippets.

@KyLeggiero
Forked from indragiek/NSWindow+Fade.h
Last active September 23, 2022 16:00
Show Gist options
  • Save KyLeggiero/1ec89e5979bf88ca13e2393fdab15ecc to your computer and use it in GitHub Desktop.
Save KyLeggiero/1ec89e5979bf88ca13e2393fdab15ecc to your computer and use it in GitHub Desktop.
NSWindow+Fade - Animator proxy based NSWindow fading
//
// NSWindow+Fade.swift
// BH Bezel Notification
//
// Created by Ben Leggiero on 2017-11-09.
// Translated to Swift 4 from the original (ObjC): https://gist.github.com/indragiek/1397050
// Copyright © 2017 Ben Leggiero. All rights reserved.
//
import Foundation
private let defaultWindowAnimationDuration: TimeInterval = 0.25
public extension NSWindow {
/// Called when an animation completes
typealias AnimationCompletionHandler = () -> Void
/// Represents a function called to make a window be presented
public enum PresentationFunction {
/// Calls `NSWindow.makeKey()`
case makeKey
/// Calls `NSWindow.makeKeyAndOrderFront(_:)`
case makeKeyAndOrderFront
/// Calls `NSWindow.orderFront(_:)`
case orderFront
/// Calls `NSWindow.orderFrontRegardless()`
case orderFrontRegardless
/// Runs the function represented by this case on the given window, passing the given selector if needed
public func run(on window: NSWindow, sender: Any?) {
switch self {
case .makeKey: window.makeKey()
case .makeKeyAndOrderFront: window.makeKeyAndOrderFront(sender)
case .orderFront: window.orderFront(sender)
case .orderFrontRegardless: window.orderFrontRegardless()
}
}
}
/// Represents a function called to make a window be closed
public enum CloseFunction {
/// Calls `NSWindow.orderOut(_:)`
case orderOut
/// Calls `NSWindow.close()`
case close
/// Calls `NSWindow.performClose()`
case performClose
/// Runs the function represented by this case on the given window, passing the given selector if needed
public func run(on window: NSWindow, sender: Any?) {
switch self {
case .orderOut: window.orderOut(sender)
case .close: window.close()
case .performClose: window.performClose(sender)
}
}
}
/// Fades this window in using the default values. Useful for NIB-style actions
@IBAction
public func fadeIn(_ sender: Any?) {
self.fadeIn(sender: sender, duration: defaultWindowAnimationDuration)
}
/// Fades this window in using the given configuration
///
/// - Parameters:
/// - sender: The message's sender, if any
/// - duration: The minimum amount of time it should to fade the window in
/// - timingFunction: The timing function of the animation
/// - startingAlpha: The alpha value at the start of the animation
/// - targetAlpha: The alpha value at the end of the animation
/// - presentationFunction: The function to use when initially presenting the window
/// - completionHandler: Called when the animation completes
public func fadeIn(sender: Any?,
duration: TimeInterval,
timingFunction: CAMediaTimingFunction? = .default,
startingAlpha: CGFloat = 0,
targetAlpha: CGFloat = 1,
presentationFunction: PresentationFunction = .makeKeyAndOrderFront,
completionHandler: AnimationCompletionHandler? = nil) {
alphaValue = startingAlpha
presentationFunction.run(on: self, sender: sender)
NSAnimationContext.runAnimationGroup({ context in
context.duration = duration
context.timingFunction = timingFunction
animator().alphaValue = targetAlpha
}, completionHandler: completionHandler)
}
/// Fades this window out using the default values. Useful for NIB-style actions
@IBAction func fadeOut(_ sender: Any?) {
self.fadeOut(sender: sender, duration: defaultWindowAnimationDuration)
}
/// Fades this window out using the given configuration
///
/// - Note: Unlike `fadeIn`, this does not take a starting alpha value. This is because the window's current
/// alpha is used. If you really want it to be different, simply change that immediately before calling
/// this function.
///
/// - Parameters:
/// - sender: The message's sender, if any
/// - duration: The minimum amount of time it should to fade the window out
/// - timingFunction: The timing function of the animation
/// - targetAlpha: The alpha value at the end of the animation
/// - presentationFunction: The function to use when initially presenting the window
/// - completionHandler: Called when the animation completes
func fadeOut(sender: Any?,
duration: TimeInterval,
timingFunction: CAMediaTimingFunction? = .default,
targetAlpha: CGFloat = 0,
resetAlphaAfterAnimation: Bool = true,
closeSelector: CloseFunction = .orderOut,
completionHandler: AnimationCompletionHandler? = nil) {
let startingAlpha = self.alphaValue
NSAnimationContext.runAnimationGroup({ context in
context.duration = duration
context.timingFunction = timingFunction
animator().alphaValue = targetAlpha
}, completionHandler: { [weak weakSelf = self] in
guard let weakSelf = weakSelf else { return }
closeSelector.run(on: weakSelf, sender: sender)
if resetAlphaAfterAnimation {
weakSelf.alphaValue = startingAlpha
}
completionHandler?()
})
}
}
public extension CAMediaTimingFunction {
public static let easeIn = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
public static let easeOut = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
public static let easenInEaseOut = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
public static let linear = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
public static let `default` = CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment