用于过滤列表内容的搜索栏 (macOS Big Sur)

Searchbar to filter contents on a list (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:一个是 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)
            }
            
        }
    }
}

搜索栏是工具栏中的一个 TextField。

在iOS,过去,我做过类似的事情:

List(ListItems.filter({ searchText.isEmpty ? true : [=12=].name.contains(searchText) })) { item in
    Text(item.name)
}

但考虑到搜索栏是工具栏中的一个项目,并且我需要使用数据模型中所有文本的搜索来过滤/重新填充列表,而不仅仅是列表,我将如何开始那个?如何过滤呢?我需要填充一个新数组吗?如何访问搜索栏上的文本?我发布的代码中是 $searchText 吗?我执行 data.filter 吗?

我 运行 没有想法可以尝试。

谢谢。

编辑:

我有这种工作,但请注意。它弄乱了 NavigationLink 的显示方式,它在文本前添加了 运行dom 空格。

代码:

var body: some View {
        NavigationView {
            List {
                ForEach(data.notes.filter { [=13=].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)
            }
        }

以下是经过编辑的答案,以免人们抱怨:

var body: some View {
        NavigationView {
                List(data.notes.filter { searchText.isEmpty ? true : [=10=].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
            })            

        }