SwiftUI WindowGroup: как ограничить количество окон?

Я создаю приложение с одним окном и хочу использовать новый жизненный цикл приложения Swift.

import SwiftUI

@main
struct SingleWindowApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Реализация по умолчанию WindowGroup позволяет несколько экземпляров окна (т.е. если вы нажмете ⌘N). Мне не удалось найти модификатор, изменяющий это поведение.

Как мне ограничить количество окон в WindowGroup одним?

5 ответов

Решение

Это должно сделать это:

import SwiftUI

@main
struct SingleWindowApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }.commands {
            CommandGroup(replacing: .newItem, addition: { })
        }
    }
}

В Xcode 14 это так же просто, как создатьSceneтолько сWindowс идентификаторомmain.

Это открывает окно и не включаетFile -> Newпункт меню.

      var body: some Scene {
  Window("My Single Window", id: "main") {
    ContentView()
  }
}

Соответствующая документация здесь: https://developer.apple.com/documentation/swiftui/window#Use-a-window-as-the-main-scene.

Поскольку я столкнулся с той же проблемой, но на iPad, где модификатор команды не действует, я обнаружил следующее: «Манифест сцены приложения» UIApplicationSceneManifestсвойство в вашем Info.plist, которое является словарем и дочерним элементом «Включить несколько окон» UIApplicationSupportsMultipleScenesкоторый установлен на YESпо умолчанию. Устанавливает этот параметр на NOдает нужный эффект :)

Каждый раз, когда вы открываете объект WindowGroup, вы можете использовать NSViewControllerRepresentable для получения экземпляра представления NSWindow.

Затем рассмотрите возможность определения внешнего объекта для хранения коллекции NSWindows. В следующий раз, когда вы откроете объект WindowGroup, если коллекция NSWindow заполнена, найдите соответствующий NSWindow для отображения. например

      if windowList.isfull {
let window = windowList.getWindow()
window.makeKey()
window.orderFront(nil)
} else {
  NSWorkspace.shared.open(url)
}

О том, как получить экземпляр NSWindow из WindowGroup, вы можете рассмотреть реализацию с открытым исходным кодом:https://github.com/happycodelucky/SwiftUIWindowBinder .

Вот как вы можете использовать обычный код SwiftUI, чтобы отключить «Файл -> Новое окно», когда главное окно открыто, и включить «Файл -> Новое окно», когда главное окно закрыто.

В этом коде, вероятно, есть некоторые крайние случаи, которые можно было бы доработать, но он работает.

      import SwiftUI

@main
struct MyApp: App {
    @State var isMainWindowOpen = false
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear {
                    print("Main window appeared")
                    self.isMainWindowOpen = true
                }
                .onDisappear {
                    print("Main window disappeared")
                    self.isMainWindowOpen = false
                }

        }.commands {
            if isMainWindowOpen {
                CommandGroup(replacing: .newItem) {
                    Button("New Window", action: {})
                        .disabled(true)
                        // This is the same keyboard shortcut as the default New Window option.
                        // We're just doing this so that our disabled dummy option shows
                        // the same shortcut visually.
                        .keyboardShortcut(KeyboardShortcut("n", modifiers: [.command]))
                }
            } else {
                // By doing nothing here, we let the default 
                // "File -> New Window" item display and handle input.
                EmptyCommands()
            }
        }
    }
}
Другие вопросы по тегам