0

In 2020 when I first touch SwiftUI, it needs to rollback to UIKit for SearchBar because in that time SwiftUI doesn't support it well.

I used below code to create searchbar in 2020

import SwiftUI

struct SearchBar: UIViewRepresentable {
    
    @Binding var text: String
    var onTextChanged: (String) -> Void
    
    class Coordinator: NSObject, UISearchBarDelegate {
        
        @Binding var text: String
        var onTextChanged: (String) -> Void
        
        init(text: Binding<String>, onTextChanged: @escaping (String) -> Void) {
            _text = text
            self.onTextChanged = onTextChanged
        }
        
        // Show cancel button when the user begins editing the search text
        func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
            searchBar.showsCancelButton = true
        }
        
        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
            text = searchText
            onTextChanged(text)
        }
        
        func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
            text = ""
            searchBar.showsCancelButton = false
            searchBar.endEditing(true)
            // Send back empty string text to search view
            onTextChanged(text)
        }
    }

I create code like below. Just want to know if we could do it natively with pure SwiftUI now. How could I trigger API request per search text change?

struct MainScreenView: View {
    @StateObject var subListViewModel = SubListViewModel()
    @State private var searchText = ""
    @State private var page = 1
    
    var body: some View {
        TabView {
            NavigationStack {
                List {
                    ForEach(subListViewModel.searchResults, id: \.self) { sub in
                        Text(sub.title)
                        Text(sub.language)
                        Text(sub.year)
                        Text(sub.imgUrl)
                    }
                }
                .navigationTitle("Search")
                .onAppear() {
                    // Pagenated
                }
            }
            .searchable(text: $searchText, prompt: "Enter movie / tv series name") {
//                ForEach(subListViewModel.searchResults, id: \.self) { result in
//                    Text("Are you looking for \(result.title)?").searchCompletion(result.title)
//                }
            }
            .tabItem {
                Image(systemName: "magnifyingglass")
                Text("Search")
            }
            
            // MARK: 2nd tab
            Text("TBD")
                .tabItem {
                    Image(systemName: "gear")
                    Text("Settings")
                }
        }
    }
}
1

1 Answer 1

0

Here is my custom solution written in SwiftUI. Searchable is not fit some of my requirements. Bind your input there. Also if you want make api calls: add binding model property, add onChange observer.

 struct SearchBarView: View {
            
            @Binding var input: String
            @Binding var yourModel: Model
                
            var body: some View {
                HStack(spacing: .zero) {
                    HStack(spacing: .zero) {
                        Image(systemName: "magnifyingglass")
                            .padding(5)
                        
                        TextField("Search Fighters", text: $input)
                        .onChange(of: input) { newValue in
                           Task {
                              let response = await makeApiCall(query: newValue)
                              yourModel = response
                           }
                        }
                    }
                    .background(.white)
                    .cornerRadius(20)
                    
                    Spacer()
                    
                    if !input.isEmpty {
                        Button("Cancel") {
                            withAnimation {
                                input = ""
                            }
                        }
                        .tint(.black)
                        .font(.body)
                        .padding(.leading, 10)
                    }
                }
                .padding(15)
                .background(Color.init(white: 0.9))
            }
        }

Then in parent view add SearchBarView and bind all necessary properties.

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

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.