はじめに
タイトルに示す通りのことを実現したくて「常に最前面 MacApp」でググったら、クリアメモリさんの『【Swift】常に最前面に表示されるOSXアプリの作り方』のページがヒットしました。この記事に書いてある手順で無事に実現できたのですが、OS他のバージョンが上がっており多少の変更が必要でしたので、元記事からの変更点をまとめておきます。
ほとんどはコンパイルエラーが出て教えてくれますが、元記事への恩返しの意味です。
前提とする環境
当方の環境(執筆時点);
- maxOS Catalina version 10.15.3
- Xcode version 11.1 (11E148)
- Apple Swift version 5.2 (swiftlang-1103.0.32.1 clang-1103.0.32.29)
変更点
AppDelegate.swift
「Stay in Front」メニューをクリックした時の、チェックオン/オフのトグル処理のコードにおいて、NSMenuItem.state
の値が変更になっています。
func toggleMenuChecked(){
if stayInFrontMenu.state == NSOnState {
stayInFrontMenu.state = NSOffState
}else if stayInFrontMenu.state == NSOffState{
stayInFrontMenu.state = NSOnState
}
}
func toggleMenuChecked() {
if stayInFrontMenu.state == .on {
stayInFrontMenu.state = .off
} else if stayInFrontMenu.state == .off {
stayInFrontMenu.state = .on
}
}
WindowController.swift
実際にウィンドウを最前面に設定する処理のコードにおいてNSWindow.Level
の値が変更になっています。
func stayInFront(){
let normalWindow = Int(CGWindowLevelForKey(.normalWindow))
let floatingWindow = Int(CGWindowLevelForKey(.floatingWindow))
if window?.level == normalWindow{
window?.level = floatingWindow
}else if window?.level == floatingWindow{
window?.level = normalWindow
}
}
func stayInFront() {
if window?.level == .normal {
window?.level = .floating
} else if window?.level == .floating {
window?.level = .normal
}
}
WindowController.swift (2箇所目)
NotificationCenterのオブザーバから呼び出されるメソッドに@objc
attributeが必要です。1 2
func nCenter(notification: NSNotification) {
stayInFront()
}
@objc
func nCenter(notification: NSNotification) {
stayInFront()
}
その他
変更点ではありませんが、コンパイルエラーが出ないので気付きにくい点として;
新しく「WindowController」というクラスを作成し、ストーリーボードで設定してあります。
この工程は省くので、各自設定しておいてください。
下図の様にカスタムクラスを設定する必要があります。これを忘れると WindowController が機能しません期待通りに動きません。
終わりに
元記事では、他にも Outlet や Action の接続手順も省略しています。もしこの記事をご覧の方で、これらの手順も知りたい方は、コメントいただければ追加いたします。
2023.7.18追記
SwiftUIで書いたMac Catalyst
アプリでの実装方法を、↓こちらに公開しました。