SwiftUI:如何在更改搜索栏的文本时触发api调用以检索数据源

问题描述 投票:0回答:2

我使用UIKit实现了一个搜索栏,将其包装在MovieSearchView中。当用户输入一些关键字时,它将在以下列表视图中显示搜索结果。

数据searchResults来自API调用self.model.getMovieSearchResults(),但是在我的代码中,从未调用过api调用。因此,我想知道当搜索栏中的搜索文本发生更改时,应将条件检查onAppear()放在哪里以触发api调用?

/ / /搜索视图

import SwiftUI

struct MovieSearchView: View {
    @ObservedObject var model = MovieListViewModel()
    @State private var searchText: String = ""

    var body: some View {
        NavigationView {
            VStack {
                SearchBar(text: $searchText)
                .onAppear() {
                    // If searchText has a value, then call api to fetch movies data.
                    if self.searchText.isEmpty == false {
                        self.model.getMovieSearchResults(for: self.searchText)
                    }
                }
                List {
                    ForEach(model.searchResults.filter {
                        self.searchText.isEmpty ? true : $0.title.lowercased().contains(self.searchText.lowercased())
                    }) { movie in
                        Text(movie.title)
                    }
                }
            }
        }
    }
}

struct MovieSearchView_Previews: PreviewProvider {
    static var previews: some View {
        MovieSearchView()
    }
}

/ / /搜索栏

import SwiftUI

struct SearchBar: UIViewRepresentable {

    @Binding var text: String

    class Coordinator: NSObject, UISearchBarDelegate {

        @Binding var text: String

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

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

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

    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.searchBarStyle = .minimal
        searchBar.autocapitalizationType = .none
        return searchBar
    }

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

更新:

只需意识到我不需要再次进行过滤,因为API调用已经从服务器返回了过滤后的搜索结果。更改代码以删除过滤器{}。我还添加了点击手势,以触发导航至电影详细信息视图并在您触及底部时调用第2页。

唯一剩下的问题是清除搜索文本后清除搜索结果。并且应该关闭键盘,它现在一直都在那儿。

import SwiftUI

struct MovieSearchView: View {
    @ObservedObject var model = MovieListViewModel()
    @State private var searchText: String = ""
    @State private var selectedId = -1
    @State private var showSheet = false
    @State private var page = 1

    var body: some View {
        NavigationView {
            VStack {
                SearchBar(text: $searchText, onTextChanged: searchMovies)
                List {
                    ForEach(0..<model.searchResults.count, id: \.self) { i in
                        MovieListRow(movie: self.model.searchResults[i])
                            .onTapGesture {
                                self.selectedId = self.model.searchResults[i].id
                                self.showSheet.toggle()
                            }
                        .onAppear() {
                            if i == self.model.searchResults.count - 1 {
                                self.page += 1
                                self.model.getMovieSearchResults(for: self.searchText, page: self.page)
                            }
                        }
                    }
                }
                .sheet(isPresented: $showSheet) {
                    SingleMovieView(movieId: self.selectedId)
                }
            }
        }
    }

    func searchMovies(for searchText: String) {
        if !searchText.isEmpty {
            self.model.getMovieSearchResults(for: self.searchText, page: self.page)
        }
    }
}

struct MovieSearchView_Previews: PreviewProvider {
    static var previews: some View {
        MovieSearchView()
    }
}

extension View {
    func Print(_ vars: Any...) -> some View {
        for v in vars { print(v) }
        return EmptyView()
    }
}
ios uikit swiftui searchbar
2个回答
0
投票

您可以使用闭包。在这里,我在搜索栏中添加了onTextChanged: (String) -> Void

MovieSearchView

import SwiftUI

struct MovieSearchView: View {
    @ObservedObject var model = MovieListViewModel()
    @State private var searchText: String = ""

    var body: some View {
        NavigationView {
            VStack {
                SearchBar(text: $searchText, onTextChanged: searchMovies)

                List {
                    ForEach(model.searchResults.filter {
                        self.searchText.isEmpty ? true : $0.title.lowercased().contains(self.searchText.lowercased())
                    }) { movie in
                        Text(movie.title)
                    }
                }
            }
        }
    }

    func searchMovies(for searchText: String) {
        if !searchText.isEmpty {
            model.getMovieSearchResults(for: searchText)
        }
    }
}

struct MovieSearchView_Previews: PreviewProvider {
    static var previews: some View {
        MovieSearchView()
    }
}

SearchBar

import SwiftUI

struct SearchBar: UIViewRepresentable {
    @Binding var text: String
    var onTextChanged: (String) -> Void

    class Coordinator: NSObject, UISearchBarDelegate {
        var onTextChanged: (String) -> Void
        @Binding var text: String

        init(text: Binding<String>, onTextChanged: @escaping (String) -> Void) {
            _text = text
            self.onTextChanged = onTextChanged
        }

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

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

    func makeUIView(context: UIViewRepresentableContext<SearchBar>) -> UISearchBar {
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.searchBarStyle = .minimal
        searchBar.autocapitalizationType = .none
        return searchBar
    }

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

0
投票

您需要使用如下所示的searchBarDelegate方法:

func searchBar(UISearchBar, shouldChangeTextIn: NSRange, replacementText: String) -> Bool

每次输入时,都会从用户那里收到回调,并且可以在此函数内将api调用激发到服务器。

© www.soinside.com 2019 - 2024. All rights reserved.