ฉันจะเพิ่มแถบเครื่องมือลงในแอป 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

ไม่ระบบนำทางของบาร์โค้ดปรับเปลี่ยนไม่พร้อมใช้งานใน macOS SwiftUI
Bijoy Thangaraj

ไม่รองรับ Toolbar ใน SwiftUI ในขณะนี้ หากคุณต้องการหนึ่ง (เพราะเหตุใด) จากนั้นใช้หนึ่งจาก AppKit ก็ยังคงมี ... จริงๆ
Asperi

@ 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())       

    }

}

การใช้วิธีนี้ยังช่วยให้คุณสามารถปรับแต่งแถบเครื่องมือได้


มีวิธีทำให้แก้ไขได้ด้วยการคลิกขวาและเลือก "กำหนดค่า Toolbar" หรือไม่? (คล้ายกับ Finder, Pages เป็นต้น)
sqwk

2
ด้วยทางออกแรกไม่มี แต่ดูวิธีการทางเลือกที่ฉันเพิ่มเข้าไปในคำตอบของฉันด้านบน ด้วยวิธีนี้คุณจะได้รับตัวเลือกในการปรับแต่งแถบเครื่องมือ
Bijoy Thangaraj

@BijoyThangaraj วิธีการเปลี่ยนStateตัวแปรของการSwiftUIViewใช้ปุ่มในแถบเครื่องมือ? ฉันพยายาม แต่รัฐไม่เปลี่ยนแปลง
อลัน

@Alan วิธีหนึ่งในการทำเช่นนั้นก็คือการโพสต์การแจ้งเตือนจาก WindowController ของคุณซึ่งคุณสามารถสังเกตได้ใน HostingController ของคุณ ใน HostingController ของคุณคุณสามารถถือ ObservableObject และปรับเปลี่ยนคุณสมบัติได้ตามการแจ้งเตือนที่ได้รับ ในที่สุดคุณสามารถส่งผ่านวัตถุที่สังเกตได้นี้ไปยัง SwiftUIV ของคุณเช่นนี้:super.init(coder: coder, rootView: AnyView(SwiftUIView().environmentObject(myObservableObject)))
Bijoy Thangaraj

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.