UISearchController 如何从 SwiftUI 激活

UISearchController how to activate from SwiftUI

我在 SwiftUI 中找到了 uiSearchController 的集成,但我不知道如何激活它?

我发现了这个:

我希望在使用 @State 更改 SwiftUI 视图中的 Bool 时 searchBar 变为活动状态。

如果我在视图修改器中添加一个 Binding 并在

中设置 searchController 的 isActive 属性
ViewControllerResolver { viewController in
    viewController.navigationItem.searchController = self.searchBar.searchController
    viewController.navigationItem.hidesSearchBarWhenScrolling = false
}

然后就不会激活了。

我对 UIKit 不是很熟悉,也许有人知道如何正确激活可以开始输入搜索的搜索栏。

class SearchBar: NSObject, ObservableObject {
    
    @Published var text: String = ""
    let searchController: UISearchController = UISearchController(searchResultsController: nil)
    
    override init() {
        super.init()
        self.searchController.obscuresBackgroundDuringPresentation = false
        self.searchController.searchResultsUpdater = self
        
    }
}

extension SearchBar: UISearchResultsUpdating {
    
    func updateSearchResults(for searchController: UISearchController) {
        // Publish search bar text changes.
        if let searchBarText = searchController.searchBar.text {
            self.text = searchBarText
        }
    }
}

final class ViewControllerResolver: UIViewControllerRepresentable {
    
    let onResolve: (UIViewController) -> Void
    
    init(onResolve: @escaping (UIViewController) -> Void) {
        self.onResolve = onResolve
    }
    
    func makeUIViewController(context: Context) -> ParentResolverViewController {
        ParentResolverViewController(onResolve: onResolve)
    }
    
    func updateUIViewController(_ uiViewController: ParentResolverViewController, context: Context) {
    }
}

class ParentResolverViewController: UIViewController {
    
    let onResolve: (UIViewController) -> Void
    
    init(onResolve: @escaping (UIViewController) -> Void) {
        self.onResolve = onResolve
        super.init(nibName: nil, bundle: nil)
    }
    
    required init?(coder: NSCoder) {
        fatalError("Use init(onResolve:) to instantiate ParentResolverViewController.")
    }
    
    override func didMove(toParent parent: UIViewController?) {
        super.didMove(toParent: parent)
        
        if let parent = parent {
            onResolve(parent)
        }
    }
}

struct SearchBarModifier: ViewModifier {
    
    let searchBar: SearchBar
    
    func body(content: Content) -> some View {
        content
            .overlay(
                ViewControllerResolver { viewController in
                    viewController.navigationItem.searchController = self.searchBar.searchController
                    viewController.navigationItem.hidesSearchBarWhenScrolling = false
                }
                .frame(width: 0, height: 0)
            )
    }
}

extension View {
    func add(_ searchBar: SearchBar) -> some View {
        return self.modifier(SearchBarModifier(searchBar: searchBar))
        
    }
}

要激活 UISearchBar(您正在使用的),只需执行以下操作:

searchController.searchBar.becomeFirstResponder()

(从这个)

现在我们需要做的就是从 SwiftUI 视图中引用 searchController.searchBar。首先,为您的 SearchBar class.

添加一个函数
class SearchBar: NSObject, ObservableObject {
    
    @Published var text: String = ""
    let searchController: UISearchController = UISearchController(searchResultsController: nil)
    
    override init() {
        super.init()
        self.searchController.obscuresBackgroundDuringPresentation = false
        self.searchController.searchResultsUpdater = self
    }
    
    /// add this function
    func activate() {
        searchController.searchBar.becomeFirstResponder()
    }
}

然后,调用它。我认为这比设置 @State 更好,但如果您需要,请告诉我,我会编辑我的答案。

struct ContentView: View {
    @StateObject var searchBar = SearchBar()
    
    var body: some View {
        NavigationView {
            Button(action: {
                searchBar.activate() /// activate the search bar
            }) {
                Text("Activate search bar")
            }
            .modifier(SearchBarModifier(searchBar: searchBar))
            .navigationTitle("Navigation View")
        }
    }
}

结果: