SwiftUI:如何过滤 ForEach 中的绑定值?
SwiftUI: How to filter Binding value in ForEach?
我需要通过从 SearchBar 搜索来过滤 ForEach 中的绑定,但它给了我一个错误。我不确定这在 SwiftUI 中是否可行,但如果您知道我可以过滤的方式,请告诉我。如果有任何帮助,我将不胜感激。
下面是我在 ForEach 中放入的结构:
struct Test: Identifiable {
let id = UUID()
var number: Int
var text: String
}
这是使用 ForEach 的视图:
struct ContentView: View {
@State var test = [
Test(number: 1, text: "1"),
Test(number: 2, text: "2"),
Test(number: 3, text: "3"),
Test(number: 4, text: "4"),
Test(number: 5, text: "5"),
Test(number: 6, text: "6")
]
@State private var searchText = ""
@State private var placeholder = "Search..."
var body: some View {
NavigationView{
VStack{
SearchBar(text: $searchText, placeholder: $placeholder)
List {
ForEach($test.filter {
([=11=].text.lowercased().contains(searchText.lowercased()) || searchText == ""}) { $data in
TestView(test: $data)
}
}
}
}
}
}
这是我的搜索栏:
struct SearchBar: UIViewRepresentable {
@Binding var text: String
@Binding var placeholder: String
class Coordinator: NSObject, UISearchBarDelegate {
@Binding var text: String
@Binding var placeholder: String
init(text: Binding<String>, placeholder: Binding<String>) {
_text = text
_placeholder = placeholder
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(true, animated: true)
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: true)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
}
func makeCoordinator() -> SearchBar.Coordinator {
return Coordinator(text: $text, placeholder: $placeholder)
}
func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
let sb = UISearchBar(frame: .zero)
sb.placeholder = context.coordinator.placeholder
sb.delegate = context.coordinator
return sb
}
func updateUIView(_ uiView: UISearchBar, context: Context) {
uiView.text = text
}
}
我认为问题不在于过滤本身,而在于 ForEach
拒绝的 .lowercased()
。有一种更简单的方法,而不是试图强制这样做。使用执行过滤的计算变量,然后滚动您自己的 Binding
以像这样发送到视图:
struct ContentView: View {
@State var testArray = [
Test(number: 1, text: "1"),
Test(number: 2, text: "2"),
Test(number: 3, text: "3"),
Test(number: 4, text: "4"),
Test(number: 5, text: "5"),
Test(number: 6, text: "6")
]
@State private var searchText = ""
@State private var placeholder = "Search..."
var filteredTest: [Test] {
// If you want to return no items when there is no matching filter use this:
testArray.filter { ([=10=].text.lowercased().contains(searchText.lowercased()))}
// If you want the whole array unless the filter matches use this:
let returnTestArray = testArray.filter { ([=10=].text.lowercased().contains(searchText.lowercased()))}
guard !returnTestArray.isEmpty else { return testArray }
return returnTestArray
}
var body: some View {
NavigationView{
VStack{
SearchBar(text: $searchText, placeholder: $placeholder)
List {
ForEach(filteredTest) { test in
TestView10(test: Binding<Test> (
get: { test },
set: { newValue in
if let index = testArray.firstIndex(where: { [=10=].id == newValue.id } ) {
testArray[index] = newValue
}
}
))
}
}
}
}
}
}
我还重命名了你的数据数组 testArray
以更好地反映它是什么,在 ForEach
中,data
现在变成了 test
。
我需要通过从 SearchBar 搜索来过滤 ForEach 中的绑定,但它给了我一个错误。我不确定这在 SwiftUI 中是否可行,但如果您知道我可以过滤的方式,请告诉我。如果有任何帮助,我将不胜感激。
下面是我在 ForEach 中放入的结构:
struct Test: Identifiable {
let id = UUID()
var number: Int
var text: String
}
这是使用 ForEach 的视图:
struct ContentView: View {
@State var test = [
Test(number: 1, text: "1"),
Test(number: 2, text: "2"),
Test(number: 3, text: "3"),
Test(number: 4, text: "4"),
Test(number: 5, text: "5"),
Test(number: 6, text: "6")
]
@State private var searchText = ""
@State private var placeholder = "Search..."
var body: some View {
NavigationView{
VStack{
SearchBar(text: $searchText, placeholder: $placeholder)
List {
ForEach($test.filter {
([=11=].text.lowercased().contains(searchText.lowercased()) || searchText == ""}) { $data in
TestView(test: $data)
}
}
}
}
}
}
这是我的搜索栏:
struct SearchBar: UIViewRepresentable {
@Binding var text: String
@Binding var placeholder: String
class Coordinator: NSObject, UISearchBarDelegate {
@Binding var text: String
@Binding var placeholder: String
init(text: Binding<String>, placeholder: Binding<String>) {
_text = text
_placeholder = placeholder
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
text = searchText
}
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(true, animated: true)
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
searchBar.setShowsCancelButton(false, animated: true)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
}
}
func makeCoordinator() -> SearchBar.Coordinator {
return Coordinator(text: $text, placeholder: $placeholder)
}
func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
let sb = UISearchBar(frame: .zero)
sb.placeholder = context.coordinator.placeholder
sb.delegate = context.coordinator
return sb
}
func updateUIView(_ uiView: UISearchBar, context: Context) {
uiView.text = text
}
}
我认为问题不在于过滤本身,而在于 ForEach
拒绝的 .lowercased()
。有一种更简单的方法,而不是试图强制这样做。使用执行过滤的计算变量,然后滚动您自己的 Binding
以像这样发送到视图:
struct ContentView: View {
@State var testArray = [
Test(number: 1, text: "1"),
Test(number: 2, text: "2"),
Test(number: 3, text: "3"),
Test(number: 4, text: "4"),
Test(number: 5, text: "5"),
Test(number: 6, text: "6")
]
@State private var searchText = ""
@State private var placeholder = "Search..."
var filteredTest: [Test] {
// If you want to return no items when there is no matching filter use this:
testArray.filter { ([=10=].text.lowercased().contains(searchText.lowercased()))}
// If you want the whole array unless the filter matches use this:
let returnTestArray = testArray.filter { ([=10=].text.lowercased().contains(searchText.lowercased()))}
guard !returnTestArray.isEmpty else { return testArray }
return returnTestArray
}
var body: some View {
NavigationView{
VStack{
SearchBar(text: $searchText, placeholder: $placeholder)
List {
ForEach(filteredTest) { test in
TestView10(test: Binding<Test> (
get: { test },
set: { newValue in
if let index = testArray.firstIndex(where: { [=10=].id == newValue.id } ) {
testArray[index] = newValue
}
}
))
}
}
}
}
}
}
我还重命名了你的数据数组 testArray
以更好地反映它是什么,在 ForEach
中,data
现在变成了 test
。