如何在macOS上使用SwiftUI搜索表格?

4
在iOS和iPadOS 15上使用SwiftUI,我们可以使用“searchable”修饰符添加搜索栏以过滤列表:
struct ContentView: View {

    @Environment(\.managedObjectContext) private var viewContext

    @State private var searchTerm = ""
    @State private var selection = Set<Video.ID>()

    private var fetchRequest: FetchRequest<Video>

    private var searchResults: [Video] {
        if searchTerm.isEmpty {
            return fetchRequest.wrappedValue.filter { _ in true }
        } else {
            return fetchRequest.wrappedValue.filter { $0.matching(searchTerm) }
        }
    }

    var body: some View {
        NavigationView {
            List {
                ForEach(searchResults) { item in
                    VideoListCellView(video: item)
                }
            }.searchable(text: $searchTerm, prompt: "Video name") // <-- HERE
        }
    }

}

然而,在 macOS 上,新的 Table 容器不支持 searchable 修饰符:

struct ContentView: View {

    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(sortDescriptors: [SortDescriptor(\.addDate, order: .reverse)], animation: .default)
    private var videos: FetchedResults<Video>

    @State
    private var selection = Set<Video.ID>()

    var body: some View {
        NavigationView {
            Table(videos, selection: $selection, sortOrder: $videos.sortDescriptors) {
                TableColumn("Title") {
                    Text($0.title)
                }

                TableColumn("Added") {
                    Text($0.addDate)
                }.width(120)

                TableColumn("Published") {
                    Text($0.publishedAt)
                }.width(120)

                TableColumn("Duration") {
                    Text($0.duration)
                }.width(50)
            }.searchable(text: $searchTerm, prompt: "Video name") // <-- GENERATES ERROR
        }
    }

}

尝试使用它会在var body: some View中产生编译错误:
The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions

有没有其他方法可以在 macOS 上搜索 Table,或者这个功能还没有被支持?


1
你尝试过将searchable修饰符应用于NavigationView而不是表格吗?这可能会被SwiftUI的编译器视为更简单,应该在相同位置(窗口工具栏的尾随边缘)显示搜索栏。 - ScottM
1
根据苹果文档:https://developer.apple.com/documentation/swiftui/view/searchable(_:text:placement:suggestions:)-7g7oo,`searchable` 在 macOS 12+ 上受支持。 - workingdog support Ukraine
2个回答

2
解决方案是在NavigationView中添加.searchable修饰符,而不是在Table中添加,正如Scott所建议的那样:
struct ContentView: View {

    @Environment(\.managedObjectContext) private var viewContext

    @FetchRequest(sortDescriptors: [SortDescriptor(\.addDate, order: .reverse)], animation: .default)
    private var videos: FetchedResults<Video>

    @State private var selection = Set<Video.ID>()
    @State private var searchTerm = ""

    private var searchResults: [Video] {
        if searchTerm.isEmpty {
            return videos.filter { _ in true }
        } else {
            return videos.filter { $0.matching(searchTerm) }
        }
    }

    var body: some View {
        NavigationView {
            Table(searchResults, selection: $selection, sortOrder: $videos.sortDescriptors) {
                TableColumn("Title", value: \.title) {
                    Text($0.title)
                }

                TableColumn("Added", value: \.addDate) {
                    Text($0.addDate)
                }.width(120)

                TableColumn("Published", value: \.publishedAt) {
                    Text($0.publishedAt)
                }.width(120)

                TableColumn("Duration") {
                    Text($0.duration)
                }.width(50)
            }
        }.searchable(text: $searchTerm, prompt: "Video name") // <-- HERE
    }

}

今天我终于成功让这个解决方案工作了,当我直接在“Table”上放置“.searchable”时。 - Joakim Danielson
我测试了一个带有.searchable修饰符的表格。它可以编译,但不需要使用它来使搜索功能正常工作。 - claude31

0

您可以通过使用特定的绑定变量更新获取请求的谓词来解决此问题。

下面的解决方案基于2021 WWDC视频将Core Data并发性带入Swift和SwiftUI中的一个示例,其中它被用于列表,这也是我使用它的方式,但我在我的表格上进行了测试,效果同样出色。

@State private var searchText: String = ""
var query: Binding<String> {
    Binding {
        searchText
    } set: { newValue in
        searchText = newValue
        if newValue.isEmpty {
            videos.nsPredicate = NSPredicate(value: true)
        } else {
            videos.nsPredicate = NSPredicate(format: "name BEGINSWITH[c] %@", newValue)
        }
    }
}

然后您可以将此变量传递给.searchable

Table(videos, selection: $selection, sortOrder: $videos.sortDescriptors) {
    // ...
}
.searchable(text: query, prompt: "Search instrument")

这种解决方案的缺点是每输入一个字母就会执行一次新的获取请求。我尝试了一个快速修复方法,即在query set方法的else中添加if newValue.count < 3 { return },它可以工作,但可能是一个不好的限制,也许可以通过使用Combine实现更高级的功能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接