繁体   English   中英

SwiftUI:如何过滤 ForEach 中的绑定值?

[英]SwiftUI: How to filter Binding value in ForEach?

我需要通过从 SearchBar 中搜索来过滤 ForEach 中的绑定,但这给了我一个错误。 我不确定这在 SwiftUI 中是否可行,但如果你知道我可以过滤的方式,请告诉我。 我会非常感谢任何帮助。

这是我在 ForEach 中放入的 struct 的样子:

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 {
                        ($0.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 { ($0.text.lowercased().contains(searchText.lowercased()))}
        
        // If you want the whole array unless the filter matches use this:
        let returnTestArray = testArray.filter { ($0.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: { $0.id == newValue.id } ) {
                                    testArray[index] = newValue
                                }
                            }
                        ))
                    }
                }
            }
        }
    }
}

我还重命名了您的数据数组testArray以更好地反映它的内容,并且在ForEach中, data现在变为test

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM