🐰
NSWindowのズームアニメーションを変更する小技
ウインドウの「拡大/縮小」(英語では“Zoom”)または信号機ボタンの緑色プラスボタン(Optionキーを押すとフルスクリーンボタンがプラスボタンに変化)を押した時のズームアニメーションを変更するには、次のようにします。
アニメーションの秒数を変更
animationResizeTime(_:)
で新フレームと現フレームの差分から適度な秒数を算出します。
デフォルト実装では UserDefaults の NSWindowResizeTime (=0.20) を使用します。この値は150px分がリサイズに要する時間としてシステムで定義されているようです。
import Cocoa
class CustomWindow: NSWindow {
override func animationResizeTime(_ newFrame: NSRect) -> TimeInterval {
3.0
}
}
CoreAnimationを使ってバウンス効果付きに変更/イージング関数を変更
import Cocoa
class CustomWindow: NSWindow {
override func setFrame(_ frameRect: NSRect, display displayFlag: Bool, animate animateFlag: Bool) {
if !animateFlag || NSWorkspace.shared.accessibilityDisplayShouldReduceMotion {
// アニメーションなし
setFrame(frameRect, display: displayFlag)
}
else {
let anim = CASpringAnimation(perceptualDuration: 1.0, bounce: 0.5)
anim.timingFunction = CAMediaTimingFunction.easeOutQuint()
animations = ["frame" : anim]
animator().setFrame(frameRect, display: displayFlag)
}
}
}
import QuartzCore
extension CAMediaTimingFunction {
static func easeOutQuint() -> CAMediaTimingFunction {
// https://easings.net/ja#easeOutQuint
return CAMediaTimingFunction(controlPoints: 0.22, 1, 0.36, 1)
}
}
NSAnimationContextを使って秒数とイージング関数を変更
import Cocoa
class CustomWindow: NSWindow {
override func setFrame(_ frameRect: NSRect, display displayFlag: Bool, animate animateFlag: Bool) {
if !animateFlag || NSWorkspace.shared.accessibilityDisplayShouldReduceMotion {
// アニメーションなし
setFrame(frameRect, display: displayFlag)
}
else {
NSAnimationContext.runAnimationGroup { ctx in
ctx.timingFunction = CAMediaTimingFunction.easeOutQuint()
ctx.allowsImplicitAnimation = true
ctx.duration = animationResizeTime(frameRect)
// super の `animate` 付きメソッドを使うとアニメーションが一瞬固まる現象があるので、`animate`なし版を使用すること
setFrame(frameRect, display: displayFlag)
}
}
}
}
補足1:アクセシビリティの「視差効果を減らす」に対応する
NSWorkspace.shared.accessibilityDisplayShouldReduceMotion
でBool値が取れるので、これがtrueの時にはアニメーションを無効化するか、ディゾルブなどの視覚刺激が少ないアニメーションに変更しましょう。
補足2:NSWindowResizeTimeはコマンドライン引数やUserDefaultsとしてもセットできる
どちらかというとこの方法の方が有名ですが、コマンドライン引数(Launch Arguments)で渡したり、defaultsコマンドでUserDefaultsに書き込む値としてもセットできます。
## ウインドウリサイズのアニメーションを実質的に無効化する
defaults write <DOMAIN> NSWindowResizeTime -float 0.001
Discussion