2020年我第一次接触SwiftUI的时候,SearchBar需要回滚到UIKit,因为当时SwiftUI对它的支持还不是很好。
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)
}
}
我创建如下代码。只是想知道我们现在是否可以使用纯 SwiftUI 本地完成它。如何在每次搜索文本更改时触发 API 请求?
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")
}
}
}
}
这是我用 SwiftUI 编写的自定义解决方案。可搜索不符合我的某些要求。 将您的输入绑定在那里。另外,如果你想进行 api 调用: 添加绑定模型属性, 添加 onChange 观察者。
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))
}
}
然后在父视图中添加SearchBarView并绑定所有必要的属性。