SwiftUI 从另一个视图中捕获 Picker 值

SwiftUI Catch the Picker value from another view

我需要向选择器添加搜索栏和零值。我想创建一个自定义选择器并在任何地方使用它以避免代码重复。我能够使用 and this 代码创建一个选择器,但我找不到如何捕获我在另一个视图中选择的值。

此代码帮助我在选择器中进行搜索。

    struct SearchBar: UIViewRepresentable {

    @Binding var text: String
    var placeholder: String

    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator

        searchBar.placeholder = placeholder
        searchBar.autocapitalizationType = .none
        searchBar.searchBarStyle = .minimal
        return searchBar
    }

    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext<SearchBar>) {
        uiView.text = text
    }

    func makeCoordinator() -> SearchBar.Coordinator {
        return Coordinator(text: $text)
    }

    class Coordinator: NSObject, UISearchBarDelegate {

        @Binding var text: String

        init(text: Binding<String>) {
            _text = text
        }

        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
        }
    }
}

这是我创建的自定义选择器。

struct CustomPicker<Item>: View where Item: Hashable {
    let items: [Item]
    let title: String
    let text: KeyPath<Item, String>
    let needOptional: Bool
    let needSearchBar: Bool
    
    @State var item: Item? = nil
    @State var searchText: String = ""
    
    var filteredItems: [Item] {
        items.filter {
            searchText.isEmpty ? true : [=11=][keyPath: text].lowercased().localizedStandardContains(searchText.lowercased())
        }
    }
    
    var body: some View {
        Picker(selection: $item, label: Text(title)) {
            if needSearchBar {
                SearchBar(text: $searchText, placeholder: "Search")
                    .padding(.horizontal, -12)
            }
            
            if needOptional {
                Text("[none]").tag(nil as Item?)
                    .foregroundColor(.red)
            }
            
            ForEach(filteredItems, id: \.self) { item in
                Text(item[keyPath: text])
                    .tag(item as Item?)
            }
        }
        .onAppear{
            searchText = ""
        }
    }
}

用法

国家模型示例

struct Country: Codable, Identifiable, Hashable {
    let id = UUID()
    let name: String

    enum CodingKeys: String, CodingKey {
        case id, name
    }
}

在内容视图中

Form {
CustomPicker(items: countryArray, title: "Country", text: \Country.name, needOptional: true, needSearchBar: true)
}

如何在 ContentView 中捕获选定的项目(可选)?

使用@Binding绑定您的物品。

struct CustomPicker<Item>: View where Item: Hashable {
    let items: [Item]
    let title: String
    let text: KeyPath<Item, String>
    let needOptional: Bool
    let needSearchBar: Bool
    
    @Binding var item: Item? // <--Here
    @State var searchText: String = ""
    
    
    //-----Other code---------//

并在内容视图中使用 @State 获取所选值。

struct ContentView: View {
    
    @State private var selectedItem: Country? //<-- Here
    
    private let countryArray: [Country] = [.init(name: "A"), .init(name: "B")]
    
    var body: some View {
        Form {
            CustomPicker(items: countryArray, title: "Country", text: \Country.name, needOptional: true, needSearchBar: true, item: $selectedItem) // <-- Here
            if let selectedItem = selectedItem {
                Text(selectedItem.name)
            }
        }
    }
}