Панель поиска для фильтрации содержимого в списке (macOS Big Sur)

#swift #macos #swiftui #macos-big-sur

Вопрос:

Я пытаюсь реализовать поиск в модели данных с помощью панели поиска.

Моя модель данных представляет собой следующую структуру:

 struct NoteItem: Codable, Hashable, Identifiable {
    let id: UUID
    var text: String
    var date = Date()
    var dateText: String {
        let df = DateFormatter()
        df.dateFormat = "EEEE, MMM d yyyy, h:mm a"
        return df.string(from: date)
    }
    var tags: [String] = []
    var filename: String = ""
    var changed: Bool = false
}
 

Приложение выполняет итерацию по каждому элементу модели данных и заполняет список, в NavigationLink котором есть два Text элемента : один с первой строкой a TextEditor , а другой с datamodel.dateText . Каждый элемент в списке указывает на другое представление, в котором TextEditor отображается полный datamodel.text

Поиск, который я пытаюсь добавить, будет только включен datamodel.text . Код выглядит следующим образом:

 struct AllNotes: View {
    @EnvironmentObject private var data: DataModel
    ...

    var body: some View {
        NavigationView {
            List(data.notes) { note in
                NavigationLink(
                    destination: NoteView(note: note, text: note.text),
                    tag: note.id,
                    selection: $selectedNoteId
                ) {
                    VStack(alignment: .leading) {
                        Text(getTitle(noteText: note.text)).font(.body).fontWeight(.bold)
                        Text(note.dateText).font(.body).fontWeight(.light)
                    }
                    .padding(.vertical, 10)
                }
            }
            .listStyle(InsetListStyle())
            .frame(minWidth: 250, maxWidth: .infinity)
        }
        .toolbar {
            ToolbarItem(placement: .automatic) {
                TextField("Search...", text: $searchText)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                    .frame(minWidth: 200)
            }
            
        }
    }
}
 

Панель поиска-это текстовое поле на панели инструментов.

В iOS в прошлом я делал что-то подобное:

 List(ListItems.filter({ searchText.isEmpty ? true : $0.name.contains(searchText) })) { item in
    Text(item.name)
}
 

Но, учитывая, что панель поиска-это элемент на панели инструментов, и что мне нужно отфильтровать / повторно заполнить список поиском по всему тексту в модели данных, а не только по списку, как бы я вообще начал это делать? Как его отфильтровать? Нужно ли мне заполнять новый массив? Как я могу получить доступ к тексту на панели поиска? это $searchText в коде, который я опубликовал? Выступаю ли я data.filter ?

У меня закончились идеи, чтобы попробовать.

Спасибо.

Редактировать:

У меня есть такая работа, но обратите внимание, на самом деле. Это портит способ NavigationLink отображения, добавляет случайные пробелы перед текстом.

код:

 var body: some View {
        NavigationView {
            List {
                ForEach(data.notes.filter { $0.text.contains(searchText) || searchText.isEmpty }) { note in
                NavigationLink(
                    destination: NoteView(note: note, text: note.text),
                    tag: note.id,
                    selection: $selectedNoteId
                ) {
                    VStack(alignment: .leading) {
                        Text(getTitle(noteText: note.text)).font(.body).fontWeight(.bold)
                        Text(note.dateText).font(.body).fontWeight(.light)
                    }
                    .padding(.vertical, 10)
                }
            }
            .listStyle(InsetListStyle())
            .frame(minWidth: 250, maxWidth: .infinity)
            .alert(isPresented: $showAlert, content: {
                alert
            })            

            Text("Create a new note...")
                .frame(maxWidth: .infinity, maxHeight: .infinity)
            }
        }
 

Комментарии:

1. developer.apple.com/wwdc21/10018

2. Где на этом сайте? И еще, это не macOS 12, это Биг Сур, так .searchable что не работает.

Ответ №1:

Вот отредактированный ответ, чтобы люди не жаловались:

 var body: some View {
        NavigationView {
                List(data.notes.filter { searchText.isEmpty ? true : $0.text.localizedCaseInsensitiveContains(searchText) }) { note in
                NavigationLink(
                    destination: NoteView(note: note, text: note.text),
                    tag: note.id,
                    selection: $selectedNoteId
                ) {
                    VStack(alignment: .leading) {
                        Text(getTitle(noteText: note.text)).font(.body).fontWeight(.bold)
                        Text(note.dateText).font(.body).fontWeight(.light)
                    }
                    .padding(.vertical, 10)
                }
            }
            .listStyle(InsetListStyle())
            .frame(minWidth: 250, maxWidth: .infinity)
            .alert(isPresented: $showAlert, content: {
                alert
            })            

        }
 

Комментарии:

1. @Кевин Сеймур, о чем ты говоришь. Если вы прочитали код в моем вопросе, то ответ ясен. Но поскольку я не хочу слышать жалоб, вот оно. полный ответ

2. Я согласен. Я думаю, что, возможно, я нажал не ту кнопку и удалил свой комментарий. Ваше здоровье.