0

I need to add searchbar and nil value to picker. I want to create a custom picker and use it everywhere to avoid code repetition. I was able to create a picker using this and this code, but I could not find how to capture the value I chose in another view.

This code helps me search inside the picker.

    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
        }
    }
}

This is the custom picker I created.

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 : $0[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 = ""
        }
    }
}

Usage

Country Model Example

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

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

in ContentView

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

result

How do I catch the selected Item(optional) in ContentView?

1 Answer 1

1

Use @Binding to bind your item.

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---------//

And use @State here in content view for getting selected value.

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)
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, I tried with @Binding var item: Item? = nil every time.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.