Як додати панель інструментів до програми macOS за допомогою SwiftUI?


11

Я намагаюся додати панель інструментів всередині заголовка до програми macOS за допомогою SwiftUI, щось подібне до того, що показано нижче.

Панель інструментів на заголовку в додатку macOS

Я не в змозі знайти спосіб досягти цього за допомогою SwiftUI. Наразі в моєму вікні є своя панель інструментів (у якій просто є текстове поле), але я хочу перенести її в заголовок.

Мій поточний код:

struct TestView: View {
    var body: some View {
        VStack {
            TextField("Placeholder", text: .constant("")).padding()
            Spacer()
        }
    }
}

Отже, у моєму випадку мені потрібно мати текстове поле всередині панелі інструментів.


Я говорю про SwiftUI в цілі macOS.
Bijoy Thangaraj

Ні, модифікатор навігаціїBarTitle недоступний у macOS SwiftUI.
Bijoy Thangaraj

Панель інструментів наразі не підтримується в SwiftUI. Якщо він вам справді потрібен (навіщо?), Тоді використовуйте його з AppKit, він все ще є ... дійсно.
Аспері

@Asperi Я зміг це зробити - див. Відповідь нижче. Панелі інструментів (або аксесуари до панелі заголовків) досі широко використовуються в додатках macOS, чи не так?
Bijoy Thangaraj

@Asperi Щоб використовувати той з AppKit, ви мали на увазі використання NSViewRepresentable для NSToolbar? Якщо так, я спробував цей метод, але не мав успіху. Якщо у вас є рішення таким чином, я хотів би перевірити його.
Bijoy Thangaraj

Відповіді:


6

Підхід 1:

Це робиться шляхом додавання аксесуара до рядка заголовка. Мені вдалося це зробити, змінивши файл AppDelegate.swift. Мені довелося застосувати якісь дивні накладки, щоб це виглядало правильно.

AppDelegate.swift

func applicationDidFinishLaunching(_ aNotification: Notification) {
        // Create the SwiftUI view that provides the window contents.
        let contentView = ContentView()

        // Create the titlebar accessory
        let titlebarAccessoryView = TitlebarAccessory().padding([.top, .leading, .trailing], 16.0).padding(.bottom,-8.0).edgesIgnoringSafeArea(.top)

        let accessoryHostingView = NSHostingView(rootView:titlebarAccessoryView)
        accessoryHostingView.frame.size = accessoryHostingView.fittingSize

        let titlebarAccessory = NSTitlebarAccessoryViewController()
        titlebarAccessory.view = accessoryHostingView       

        // Create the window and set the content view. 
        window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
        window.center()
        window.setFrameAutosaveName("Main Window")

        // Add the titlebar accessory
        window.addTitlebarAccessoryViewController(titlebarAccessory)

        window.contentView = NSHostingView(rootView: contentView)
        window.makeKeyAndOrderFront(nil)
    }

TitlebarAccessory.swift

import SwiftUI

struct TitlebarAccessory: View {
    var body: some View {

        TextField("Placeholder", text: .constant(""))

    }
}

Результат:

Вміст всередині панелі інструментів macOS

Підхід 2 (альтернативний метод):

Ідея тут полягає в тому, щоб зробити частину панелі інструментів за допомогою раскадровки та решти програми за допомогою SwiftUI. Це робиться шляхом створення нового додатка з розкадровкою як користувальницького інтерфейсу. Потім перейдіть до таблиці та видаліть контролер перегляду за замовчуванням та додайте новий NSHostingController. Підключіть щойно доданий хостинг-контролер до головного вікна, встановивши його зв'язок. Додайте панель інструментів до вікна за допомогою програми для створення інтерфейсів.

Конфігурація розгортки

Приєднайте до себе спеціальний клас NSHostingControllerі завантажте в нього свій погляд SwiftUI.

Приклад нижче:

import Cocoa
import SwiftUI

class HostingController: NSHostingController<SwiftUIView> {

    @objc required dynamic init?(coder: NSCoder) {
        super.init(coder: coder, rootView: SwiftUIView())       

    }

}

Використання цього підходу також дає можливість налаштувати панель інструментів.


Чи є спосіб зробити його редагованим, клацнувши правою кнопкою миші та вибравши "Налаштувати панель інструментів"? (Подібно до Finder, Pages тощо)
sqwk

2
З першим рішенням немає. Але подивіться на альтернативний підхід, який я додав до своєї відповіді вище. Таким чином, ви отримуєте можливість налаштувати панель інструментів.
Bijoy Thangaraj

@BijoyThangaraj як змінити Stateзмінні за SwiftUIViewдопомогою кнопки на панелі інструментів? Я намагався, але стан не змінюється.
Алан

@Alan, один із способів зробити це - опублікувавши повідомлення від свого WindowController, яке ви можете спостерігати у своєму HostingController. У своєму HostingController ви можете утримувати ObservableObject і змінювати його властивості на основі отриманого повідомлення. Нарешті, ви можете передати цей спостережуваний об’єкт своєму SwiftUIView так:super.init(coder: coder, rootView: AnyView(SwiftUIView().environmentObject(myObservableObject)))
Біжой Тхангарай

0

UIKit + каталізатор

https://developer.apple.com/documentation/uikit/uititlebar

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        guard let windowScene = (scene as? UIWindowScene) else { return }
        let window = UIWindow(windowScene: windowScene)

        if let titlebar = windowScene.titlebar {

            //toolbar
            let identifier = NSToolbar.Identifier(toolbarIdentifier)
            let toolbar = NSToolbar(identifier: identifier)
            toolbar.allowsUserCustomization = true
            toolbar.centeredItemIdentifier = NSToolbarItem.Identifier(rawValue: centerToolbarIdentifier)
            titlebar.toolbar = toolbar
            titlebar.toolbar?.delegate = self

            titlebar.titleVisibility = .hidden
            titlebar.autoHidesToolbarInFullScreen = true
        }

        window.makeKeyAndVisible()

    }
#if targetEnvironment(macCatalyst)
let toolbarIdentifier = "com.example.apple-samplecode.toolbar"
let centerToolbarIdentifier = "com.example.apple-samplecode.centerToolbar"
let addToolbarIdentifier = "com.example.apple-samplecode.add"

extension SceneDelegate: NSToolbarDelegate {

    func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
        if itemIdentifier == NSToolbarItem.Identifier(rawValue: toolbarIdentifier) {
            let group = NSToolbarItemGroup(itemIdentifier: NSToolbarItem.Identifier(rawValue: toolbarIdentifier), titles: ["Solver", "Resistance", "Settings"], selectionMode: .selectOne, labels: ["section1", "section2", "section3"], target: self, action: #selector(toolbarGroupSelectionChanged))

            group.setSelected(true, at: 0)

            return group
        }

        if itemIdentifier == NSToolbarItem.Identifier(rawValue: centerToolbarIdentifier) {
            let group = NSToolbarItemGroup(itemIdentifier: NSToolbarItem.Identifier(rawValue: centerToolbarIdentifier), titles: ["Solver1", "Resistance1", "Settings1"], selectionMode: .selectOne, labels: ["section1", "section2", "section3"], target: self, action: #selector(toolbarGroupSelectionChanged))

            group.setSelected(true, at: 0)

            return group
        }

        if itemIdentifier == NSToolbarItem.Identifier(rawValue: addToolbarIdentifier) {
            let barButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.add, target: self, action: #selector(self.add(sender:)))
            let button = NSToolbarItem(itemIdentifier: itemIdentifier, barButtonItem: barButtonItem)
            return button
        }

        return nil
    }

    @objc func toolbarGroupSelectionChanged(sender: NSToolbarItemGroup) {
        print("selection changed to index: \(sender.selectedIndex)")
    }

    @objc func add(sender: UIBarButtonItem) {
        print("add clicked")
    }

    func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
        [NSToolbarItem.Identifier(rawValue: toolbarIdentifier), NSToolbarItem.Identifier(rawValue: centerToolbarIdentifier), NSToolbarItem.Identifier.flexibleSpace,
            NSToolbarItem.Identifier(rawValue: addToolbarIdentifier),
            NSToolbarItem.Identifier(rawValue: addToolbarIdentifier)]
    }

    func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
        self.toolbarDefaultItemIdentifiers(toolbar)
    }

}
#endif
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.