在 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 上,searchable
新Table
容器不支持该修饰符:
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
是否有另一种Table
在 macOS上搜索 a 的方法,或者此功能尚不支持?
uj5u.com热心网友回复:
正如斯科特建议的那样,解决方案是将.searchable
修饰符添加到NavigationView
而不是Table
:
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
}
}
uj5u.com热心网友回复:
您可以通过使用特定的 Binding 变量更新获取请求的谓词来解决此问题。
以下解决方案基于 2021 年 WWDC 视频将核心资料并发性引入 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")
这个解决方案的缺点是每个输入的字母都会执行一个新的提取请求。我想速战速决通过增加if newValue.count < 3 { return }
在else
该的query
set
方法和它的作品,但它可能是一个坏的限制,也可以是更高级的可以通过合并来实作。
0 评论