SwiftUI: как использовать NSSearchToolBarItem в macOS 11?

#swiftui #toolbar #macos-big-sur #nssearchtoolbaritem

#swiftui #панель инструментов #macos-big-sur #nssearchtoolbaritem

Вопрос:

Я смотрел видео WWDC «Adopt the new look of macOS», где они представили NSSearchToolBarItem в Swift в 11:32 в видео.

Это именно то, что мне нужно сделать, но как мне добавить этот поиск на панель инструментов в SwiftUI?

Существует множество сложных примеров, но все они, похоже, были написаны до появления этого нового API. Должен быть более простой способ?

 import SwiftUI

var listItems = ["Item 1", "Item 2", "Item 3", "Item 4"]

struct ContentView: View
{
    
    @State var select: String? = "Item 1"
    @State var searchText: String = "hello"

    var body: some View
    {
        VStack
        {
            NavigationView
            {
                List
                {
                    ForEach((0..<listItems.count), id: .self)
                    {index in
                         Label(listItems[index], systemImage: "briefcase")
                    }
                }
            }
            
            .toolbar
            {
                Button(action: {})
                {
                    Label("Upload", systemImage: "square.and.pencil")
                }
                TextField("Search", text: $searchText)
            }
        }
    }
}
  

Ответ №1:

Не похоже, что существует очевидный способ сделать это NSSearchToolbarItem напрямую, но, изучая этот класс, он использует NSSearchField under the hood, который относительно прост в использовании в SwiftUI, используя NSViewRepresentable :

 struct SearchField: NSViewRepresentable {

    class Coordinator: NSObject, NSSearchFieldDelegate {
        var parent: SearchField

        init(_ parent: SearchField) {
            self.parent = parent
        }

        func controlTextDidChange(_ notification: Notification) {
            guard let searchField = notification.object as? NSSearchField else {
                print("Unexpected control in update notification")
                return
            }
            self.parent.search = searchField.stringValue
        }

    }

    @Binding var search: String

    func makeNSView(context: Context) -> NSSearchField {
        NSSearchField(frame: .zero)
    }

    func updateNSView(_ searchField: NSSearchField, context: Context) {
        searchField.stringValue = search
        searchField.delegate = context.coordinator
    }

    func makeCoordinator() -> Coordinator {
        return Coordinator(self)
    }

}
  

Затем вы можете использовать это размещенное представление непосредственно внутри ToolbarItem :

 ToolbarItem {
    SearchField(search: $filter)
        .frame(minWidth: 100, idealWidth: 200, maxWidth: .infinity)
}
  

Возможно, вы захотите немного изменить размеры (в .frame() вызове), чтобы они соответствовали выходным собственным размерам платформы, но, похоже, это довольно точно соответствует тому, как выглядит Notes.app.

Элемент панели инструментов поиска в Notes.app:

Скриншот, показывающий элемент панели инструментов поиска в Notes.app

Элемент панели инструментов поиска из приведенного выше примера кода:

Скриншот, показывающий панель инструментов поиска из примера кода