Sponsor Link
環境&対象
- macOS Monterery beta 5
- Xcode 13 beta5
- iOS 15 beta
メニュー
Apple の HIG によると、以下の3種類のメニューがあります。
- Menu bar menu
- Contextual menu
- Dock menu
この記事では、Menu bar menu について説明していきます。
メニューの種類
メニューは、以下のような構成になっています。(アプリによっては存在しないメニューがあります)
- Apple menu
- App menu
- File menu
- Edit menu
- Format menu
- View menu
- App-specific menu(s)
- Window menu
- Help menu
Xcode のメニュー構成
ちなみに、Xcode は、以下のようなメニュー構成です。
Format menu が存在せず、Find から Source Control までが、App-specific menu(s) にあたります。
SwiftUI でのメニュー構成
App テンプレートでのメニュー構成(1: non-document based)
macOS の Non-Document な App のテンプレートで作成したアプリでは、以下のメニューのみ存在します。
- Apple menu
- App menu
- File menu
- Edit menu
- Window menu
- Help menu
App テンプレートでのメニュー構成(2: document based)
macOS の Document base な App のテンプレートで作成したアプリでは、以下のメニューのみ存在します。
- Apple menu
- App menu
- File menu
- Edit menu
- Window menu
- Help menu
よくみるとサブメニューの中身は、アプリのタイプによって異なるものになっていますが、メニューバー項目としては、上記のようになっています。
メニューを追加する
テンプレートで設定されているメニューに 自分のメニューを追加する方法を説明します。
自分のメニューを表示する
.commands
SwiftUI では、Scene に .commands を使って付与することになります。
Apple のドキュメントは、こちら。
.commands は、macOS, iPadOS それぞれに応じた処理を行ってくれます。(ここでは、macOS についてのみ説明します)
CommandMenu
CommandMenu を使うことで、menu bar 上のメニューを作成することができます。
実際のメニュー項目は、View で作成します。
以下は、Menu bar 項目は、”MyMenu” で メニュー項目は、”MyCommand1″ というメニューを作成するコードです。
//
// macOSAppApp.swift
//
// Created by : Tomoaki Yagishita on 2021/09/09
// © 2021 SmallDeskSoftware
//
import SwiftUI
@main
struct macOSAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.commands {
// (1)
CommandMenu("MyMenu") {
MyCommand1()
}
}
}
}
struct MyCommand1: View {
var body: some View {
Button(action: {
print("MyCommand1")
}, label: {
// (2)
Text("MyCommand1")
})
// (3)
.keyboardShortcut("1", modifiers: [.shift, .command])
}
}
- Menu bar に “MyMenu” というメニューを指定しています
- メニューアイテムは、”MyCommand1″ として表示されます
- ショートカットとして、Shift+Command+1 を設定しています。
コマンドの処理
上記のコマンドは、Button で実装していますので、action: にコマンド処理を記述します。
サンプルのコードでは、MyCommand1 と コンソールに print する処理を記述しています。
複数のメニュー
.commands は、ViewBuilder のようなメソッドのため、複数のコマンドを記述することができます。
実際には、CommandsBuilder というものです。
Apple のドキュメントは、こちら。
# 最大10要素までしか記述できないところも、ViewBuilder と同じです。
この機能を使うことで、.commands 内に 複数の CommandMenu を記述することができます。
.commands {
// (1)
CommandMenu("MyMenu") {
MyCommand1()
}
CommandMenu("MyMenu2") {
MyCommand2()
}
}
メニューは、App-specific menu の場所に追加されるため、位置としては、Edit と Window の間に配置されます。
既存メニューへの追加
アプリケーションによっては、既存メニューの中に(例えば File メニュー)、App-specific なメニューを追加したい時があります。
以下は、既存メニューの中に 追加する方法です。
メニュー要素
メニュー要素自体は、同じ作りです。(ので省略です)
位置を指定したメニュー追加
CommandGroup を使用して、メニュー要素を指定した位置に配置します。
Apple のドキュメントは、こちら。
CommandGroup(after: ) を使用することで、指定要素の後に メニュー要素を配置します。
同様に、CommandGroup(before:) を使用すると 指定要素の前に、CommandGroup(replace:) を使用すると 指定要素と置き換えて メニュー要素が配置されることになります。
例として作成した MyCommand1 というメニュー要素を、”About App” の後に追加してみます。
//
// macOSAppApp.swift
//
// Created by : Tomoaki Yagishita on 2021/09/09
// © 2021 SmallDeskSoftware
//
import SwiftUI
@main
struct macOSAppApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.commands {
CommandMenu("MyMenu") {
MyCommand1()
}
CommandMenu("MyMenu2") {
MyCommand2()
}
CommandGroup(after: .appInfo) {
MyCommand1()
}
}
}
}
// ommit MyCommand1, MyCommand2
配置時に参照できるメニュー
配置時に参照・置換できるメニューは以下の通りです。
- appInfo
- appSettings
- systemServices
- appVisibility
- appTermination
- newItem
- saveItem
- importExport
- printItem
- undoRedo
- pasteboard
- textEditing
- textFormatting
- toolbar
- sidebar
- windowSize
- windowList
- windowArrangement
- help
Apple のドキュメントは、こちら。
用意されている CommandGroup
SwiftUI ではいくつかのメニューセットが用意されています。
- SidebarCommands
- TextEditingCommands
- TextFormattingCommands
- ToolbarCommands
- ImportFromDevicesCommands
- EmptyCommands
.commands を使って、上記 CommandGroup を設定することで、それぞれのメニューが表示されるようになります。
# EmptyCommands の使用目的は、ちょっとわかりません・・・・ 設定してもメニューは追加されません。
まとめ:SwiftUI でのコマンドの扱い方
- Scene に .commands で設定する
- CommandMenu がメニュー項目になる
- CommandGroup を使用すると既存メニューに追加したり、置き換えることができる
説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。
Sponsor Link