Add Search Bar on the picker list SwiftUI
Asked Answered
I

2

6

I tap on picker it will open screen with list of element on that screen, can we add Search Bar?

I implemented Country Picker, in the country list I am showing country name and country code so on that list screen add Search bar find out country easily.

struct ContentView: View {

    //All Country get from the plist with country Code and Coutnry Name.
    let countyList = Country().getAllCountyInfo()

    // Selected Country
    @State private var selectedCountry = 0

    var body: some View {


        NavigationView {
            Form {
                Picker(selection: $selectedCountry, label: Text("Country")) {

                    ForEach(countyList) { country in

                        HStack{
                            Text(country.countryName ?? "")
                            Spacer()
                            Text(country.countryCode ?? "")
                        }
                    }
                }
            }
            .navigationBarTitle("Select country picker")
        }

    }
}

enter image description here

by run above code it will open a country list like above screen.

on the above screen (country list).

How can I add search bar to filter country data?

Idiocy answered 1/2, 2020 at 12:37 Comment(4)
Please add your code and what you have tried.Grater
Please check this link you can able to user search bar in SwiftUI github.com/rathodmayur93/SearchBarSwiftUIEvolutionary
I would like to know whether you've managed to solve this?Corelli
@FaaiezSallie Add search bar inside the Picker.Idiocy
H
5

You can add a TextField that would act as a searchbar in the picker's body:

SearchBar code:

struct SearchBar: View {
    @Binding var text: String
    @State var isEditing = false
    var body: some View {
        HStack {
            TextField("Search Countries", text: $text)
                .padding(7)
                .padding(.horizontal, 25)
                .background(Color.gray)
                .cornerRadius(8)
                .overlay(
                    HStack {
                        Image(systemName: "magnifyingglass")
                            .foregroundColor(.gray)
                            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
                            .padding(.leading, 8)
                        if isEditing {
                            Button(action: {
                                text = ""
                            }) {
                                Image(systemName: "multiply.circle.fill")
                                    .foregroundColor(.gray)
                                    .padding(.trailing, 8)
                            }
                        }
                    }
                ).padding(.horizontal, 10)
                .onTapGesture {
                    isEditing = true
                }
            if isEditing {
                Button(action: {
                    UIApplication.shared.endEditing(true)
                    isEditing = false
                    text = ""
                }) {
                    Text("Cancel")
                }.padding(.trailing, 10)
                .transition(.move(edge: .trailing))
                .animation(.default)
            }
        }
    }
}

extension UIApplication {
    func endEditing(_ force: Bool) {
        self.windows
            .filter{$0.isKeyWindow}
            .first?
            .endEditing(force)
    }
}

extension View {
    func resignKeyboardOnDragGesture() -> some View {
        gesture(
            DragGesture()
                .onChanged { _ in
                    UIApplication.shared.endEditing(true)
                }
        )
    }
}

Picker with Search Bar:

struct ContentView: View {
    @State var data: [String] = //your data
    @State var searchText = ""
    @State var selection: String?
    var displayedData: [String] {
        return data.filter({searchText.isEmpty ? true: $0.lowercased().contains(searchText.lowercased())})
    }
    var body: some View {
        Picker("Title", selection: $selection) {
            SearchBar(text: $searchText)
            ForEach(displayedData, id: \.self) { item in
                Text(item)
                    .tag(item)
            }.resignKeyboardOnDragGesture()
        }
    }
}
Hertfordshire answered 31/8, 2020 at 15:57 Comment(1)
How to make it work past iOS 15 as it gives " 'windows' was deprecated in iOS 15.0: Use UIWindowScene.windows on a relevant window scene instead " deprecation note?Hemimorphite
J
5

I solve this in my blog post here: https://roddy.io/2020/09/07/add-search-bar-to-swiftui-picker/

Create the UIViewRepresentable:

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

And then it's easy to embed it in your Picker:

struct FormView: View {

    let countries = ["Brazil", "Canada", "Egypt", "France", "Germany", "United Kingdom"]

    @State private var pickerSelection: String = ""
    @State private var searchTerm: String = ""
    
    var filteredCountries: [String] {
        countries.filter {
            searchTerm.isEmpty ? true : $0.lowercased().contains(searchTerm.lowercased())
        }
    }

    var body: some View {
        NavigationView {
            Form {
                Picker(selection: $pickerSelection, label: Text("")) {
                    SearchBar(text: $searchTerm, placeholder: "Search Countries")
                    ForEach(filteredCountries, id: \.self) { country in
                        Text(country).tag(country)
                    }
                }
            }
        }
    }
}
Jacquenette answered 6/12, 2020 at 1:16 Comment(4)
This doesn't seem to work. The list is not refreshed automatically when typing. XCode 12.4Scrawny
It works for me. I just cut and pasted his code directly from that website he linked in to new Xcode project (Xcode 12.5) and ran it on a physical iPhone 12 Pro Max (iOS 14.2) and it appears to work as described.Parkinson
@Scrawny I had trouble too but got it to work perfectly by putting it in it's own ViewAlbin
How to use it in iOS 15 and aboveKaye

© 2022 - 2024 — McMap. All rights reserved.