WWDC Quick Look 💓 By SwiftGGTeam
SwiftUI on the Mac: Build the fundamentals

SwiftUI on the Mac: Build the fundamentals

元の動画を見る

ハイライト

優れた Mac アプリには、柔軟性 (カスタマイズ可能)、親しみやすい (システム規約に従っている)、広大 (大きな画面を活用している)、正確 (高い情報密度) という 4 つの共通の特徴があります。セッションでは、ガーデニング管理アプリを使用して SwiftUI でこれらの原則を実装する方法を示します。

主な内容

macOS Monterey の SwiftUI の改善により、実稼働グレードの Mac アプリの構築に真に使用できるようになりました。Session では、最初から構築したガーデニング追跡アプリを実行例として使用します。

SwiftUI の 4 つの基本原則の実装:

  • 柔軟: 使用します@SceneStorage再起動後もユーザーのインターフェース構成が維持されるように、サイドバーの展開状態と選択した項目を保存します。
  • おなじみ: 使用しますCommandsモディファイアは標準のメニュー バーを構築します。ToolbarItem合意された場所に設置する
  • 広範: 使用しますTable複数列のデータを表示します。DisclosureGroupコンテンツ表示の制御
  • 正確: テーブルのコンパクトな行の高さ、サイドバーの最小幅の設定

##詳細

サイドバー: アウトライン ビューの構築

Macアプリのサイドバーをよく使うDisclosureGroupアウトラインビューを実装します。協力する@SceneStorage展開状態を保存できます (06:09)。

@SceneStorage("expansionState") private var expansionState = Set<String>()

var body: some View {
    List {
        DisclosureGroup("Current Year", isExpanded: $isCurrentExpanded) {
            ForEach(currentYearGardens) { garden in
                Label(garden.name, systemImage: "leaf")
                    .tag(garden.id)
            }
        }
        DisclosureGroup("History") {
            GardenHistoryOutline()
        }
    }
    .frame(minWidth: 150)
}

キーポイント:

  • @SceneStorageアプリの終了時に状態を自動的に保存し、再起動後に復元します
  • DisclosureGroup折りたたみ可能なアウトラインビューを提供します
  • tag()協力するselectionバインディングはキーボード ナビゲーションと選択された状態をサポートします

テーブル: 複数列のデータ表示

Tableこれは、macOS Monterey の新しいコンポーネントであり、次のようになります。NSTableView(09:14)。

Table(plants, selection: $selectedPlant, sortOrder: $sortOrder) {
    TableColumn("Name", value: \.name)
    TableColumn("Variety", value: \.variety)
    TableColumn("Days to Maturity") { plant in
        Text("\(plant.daysToMaturity)")
    }
}

キーポイント:

  • Table複数列表示をサポートします。Listより複雑なデータに適しています
  • selectionバインディングは単一または複数の選択をサポートします
  • sortOrderバインディングは列のソートを自動的にサポートします
  • 自動的にダウングレードList

ツールバー: ツールバーの構成

ツールバーは、Mac ユーザーが機能を見つけるための標準的な場所です (11:21)。

Table(plants) {
    // 列定义...
}
.toolbar {
    ToolbarItem(placement: .primaryAction) {
        Button(action: addPlant) {
            Label("Add Plant", systemImage: "plus")
        }
    }
    ToolbarItem(placement: .automatic) {
        DisplayModePicker()
    }
}

キーポイント:

  • ToolbarItemplacementツールバー内の位置を決定する
  • .primaryAction左側の目立つ位置に置きます
  • .automaticシステムに空間に基づいて位置を決定させます
  • 選択した状態に基づいてボタンを無効にすることができます

検索可能: 検索機能

Mac には常にハードウェア キーボードがあり、データをすばやく選別するには検索が効果的な方法です (12:15)。

Table(plants.filter { searchText.isEmpty || $0.name.contains(searchText) }) {
    // 列定义...
}
.searchable(text: $searchText)

キーポイント:

  • .searchableモディファイアはツールバーに検索ボックスを追加します
  • Mac の検索ボックスはツールバーの右側に固定されています
  • サポートCmd+Fショートカット キー フォーカス検索ボックス
  • フォーカスとキーボードナビゲーションを自動的に処理します

コマンド: メニューバーの設定

メニュー バーは、Mac ユーザーが機能を探索するための重要な方法です (13:17)。

@main
struct GardenApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .commands {
            SidebarCommands()
            CommandGroup(before: .newItem) {
                Button("Add Plant") {
                    // 添加植物
                }
                .keyboardShortcut("n", modifiers: .command)
            }
            CommandMenu("Plants") {
                Button("Mark as Watered") {
                    // 标记为已浇水
                }
                .keyboardShortcut("w", modifiers: [.command, .shift])
            }
        }
    }
}

キーポイント:

  • .commandsモディファイア設定メニューバー
  • SidebarCommands()標準のサイドバートグルメニューを追加
  • CommandGroup(before:)システムメニューの前にカスタムコマンドを挿入
  • CommandMenu新しいトップレベルメニューを作成する

FocusedSceneValue: ウィンドウ間の通信

マルチウィンドウ アプリのメニュー コマンドは、前景ウィンドウで動作する必要があります (14:01)。

struct GardenDetail: View {
    @Binding var garden: Garden?

    var body: some View {
        Table(plants, selection: $selectedPlants) {
            // 列定义...
        }
        .focusedSceneValue(\.selectedGarden, $garden)
        .focusedSceneValue(\.selectedPlants, $selectedPlants)
    }
}
struct PlantCommands: Commands {
    @FocusedValue(\.selectedGarden) private var focusedGarden: Binding<Garden>?

    var body: some Commands {
        CommandMenu("Plants") {
            Button("Mark as Watered") {
                focusedGarden?.wrappedValue.markAsWatered()
            }
            .disabled(focusedGarden == nil)
        }
    }
}

キーポイント:

  • @FocusedValue現在フォーカスされているウィンドウの値を読み取ります。
  • focusedSceneValueメニューコマンドへのバインディングを公開する
  • メニューコマンドはフロントウィンドウに自動的に作用します
  • ウィンドウのフォーカスを手動で追跡する必要はありません

重要ポイント

  1. @SceneStorage を使用してユーザー インターフェイスの状態を保存します: Mac アプリには複数のウィンドウがあるため、各ウィンドウの状態を個別に保存する必要があります。@SceneStorageこれは自動的に処理されるため、UserDefault を手動で読み書きする必要がなくなります。

  2. 複雑なデータを表示するには、リストではなくテーブルを使用します: 複数列の並べ替え可能なデータが必要な場合は、次を使用します。Tableの代わりにListTable情報密度を考慮して設計されており、並べ替えと選択をサポートし、自動的に次のレベルにダウングレードされます。List

  3. すべてのアクションに対するメニュー バーのショートカット: Mac ユーザーは、メニュー バーとショートカットを通じてすべての機能にアクセスできることを期待しています。アプリにツールバーがある場合でも、機能を見つけやすくするために、これらのアクションをメニュー バーで繰り返す必要があります。

  4. Searchable で検索機能を追加: Mac のツールバーには十分なスペースがあります。.searchable検索ボックスを標準の位置に表示するようにサポートCmd+F焦点を絞り、ユーザーの習慣に沿ったものにします。

  5. FocusedSceneValue を使用してウィンドウ間のコラボレーションを実現: マルチウィンドウ アプリのメニュー コマンドは、フロント ウィンドウで動作する必要があります。focusedSceneValue + @FocusedValueこれは、フォーカス追跡を手動で管理する必要なく実現されます。

関連セッション

コメント

GitHub Issues · utterances