Skip to content

Instantly share code, notes, and snippets.

@markvanwijnen
Created September 9, 2020 20:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markvanwijnen/38c630e72735444a063594eaa5a582ed to your computer and use it in GitHub Desktop.
Save markvanwijnen/38c630e72735444a063594eaa5a582ed to your computer and use it in GitHub Desktop.
Part 16 of building the NavigationSearch.
import SwiftUI
import UIKit
extension View {
func navigationSearch(text: Binding<String>, onCancelButtonClicked: @escaping () -> Void = {}, onSearchButtonClicked: @escaping () -> Void = {}) -> some View {
overlay(NavigationSearch<AnyView>(text: text, onCancelButtonClicked: onCancelButtonClicked, onSearchButtonClicked: onSearchButtonClicked).frame(width: 0, height: 0))
}
func navigationSearch<SearchResultsContent>(text: Binding<String>, onCancelButtonClicked: @escaping () -> Void = {}, onSearchButtonClicked: @escaping () -> Void = {}, @ViewBuilder searchResultsContent: @escaping () -> SearchResultsContent) -> some View where SearchResultsContent : View {
overlay(NavigationSearch<SearchResultsContent>(text: text, onCancelButtonClicked: onCancelButtonClicked, onSearchButtonClicked: onSearchButtonClicked, searchResultsContent: searchResultsContent).frame(width: 0, height: 0))
}
}
struct NavigationSearch<SearchResultsContent>: UIViewControllerRepresentable where SearchResultsContent : View {
typealias UIViewControllerType = Wrapper
@Binding var text: String
private let onCancelButtonClicked: () -> Void
private let onSearchButtonClicked: () -> Void
private let searchResultsContent: () -> SearchResultsContent?
init(text: Binding<String>, onCancelButtonClicked: @escaping () -> Void = {}, onSearchButtonClicked: @escaping () -> Void = {}, @ViewBuilder searchResultsContent: @escaping () -> SearchResultsContent? = { nil }) {
self._text = text
self.onCancelButtonClicked = onCancelButtonClicked
self.onSearchButtonClicked = onSearchButtonClicked
self.searchResultsContent = searchResultsContent
}
func makeCoordinator() -> Coordinator {
Coordinator(representable: self)
}
func makeUIViewController(context: Context) -> Wrapper {
Wrapper()
}
func updateUIViewController(_ wrapper: Wrapper, context: Context) {
wrapper.searchController = context.coordinator.searchController
wrapper.searchController?.searchBar.text = text
wrapper.navigationBarSizeToFit()
if let searchResultsContent = self.searchResultsContent() {
(wrapper.searchController?.searchResultsController as? UIHostingController<SearchResultsContent>)?.rootView = searchResultsContent
}
}
class Coordinator: NSObject, UISearchResultsUpdating, UISearchBarDelegate {
let representable: NavigationSearch
let searchController: UISearchController
init(representable: NavigationSearch) {
self.representable = representable
var searchResultsController: UIViewController? = nil
if let searchResultsContent = representable.searchResultsContent() {
searchResultsController = UIHostingController(rootView: searchResultsContent)
}
self.searchController = UISearchController(searchResultsController: searchResultsController)
super.init()
self.searchController.searchResultsUpdater = self
self.searchController.searchBar.delegate = self
self.searchController.searchBar.text = representable.text
}
// MARK: - UISearchResultsUpdating
func updateSearchResults(for searchController: UISearchController) {
guard let text = searchController.searchBar.text else { return }
DispatchQueue.main.async { [weak self] in self?.representable.text = text }
}
// MARK: - UISearchBarDelegate
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
DispatchQueue.main.async { self.representable.onCancelButtonClicked() }
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
DispatchQueue.main.async { self.representable.onSearchButtonClicked() }
}
}
class Wrapper: UIViewController {
var searchController: UISearchController? {
get {
self.parent?.navigationItem.searchController
}
set {
self.parent?.navigationItem.searchController = newValue
}
}
func navigationBarSizeToFit() {
self.parent?.navigationController?.navigationBar.sizeToFit()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment