how to display a search bar with SwiftUI

后端 未结 4 1734
深忆病人
深忆病人 2020-12-04 07:02

The new SwiftUI framework does not seem to provide a built-in search bar component. Should I use a UISearchController and wrap it in some way, or should I use a simple textf

4条回答
  •  孤城傲影
    2020-12-04 07:29

    A native Search Bar can be properly implemented in SwiftUI by wrapping the UINavigationController.

    This approach gives us the advantage of achieving all the expected behaviours including automatic hide/show on scroll, clear and cancel button, and search key in the keyboard among others.

    Wrapping the UINavigationController for Search Bar also ensures that any new changes made to them by Apple are automatically adopted in your project.

    Example Output

    Click here to see the implementation in action

    Code (wrap UINavigationController):

    import SwiftUI
    
    struct SearchNavigation: UIViewControllerRepresentable {
        @Binding var text: String
        var search: () -> Void
        var cancel: () -> Void
        var content: () -> Content
    
        func makeUIViewController(context: Context) -> UINavigationController {
            let navigationController = UINavigationController(rootViewController: context.coordinator.rootViewController)
            navigationController.navigationBar.prefersLargeTitles = true
            
            context.coordinator.searchController.searchBar.delegate = context.coordinator
            
            return navigationController
        }
        
        func updateUIViewController(_ uiViewController: UINavigationController, context: Context) {
            context.coordinator.update(content: content())
        }
        
        func makeCoordinator() -> Coordinator {
            Coordinator(content: content(), searchText: $text, searchAction: search, cancelAction: cancel)
        }
        
        class Coordinator: NSObject, UISearchBarDelegate {
            @Binding var text: String
            let rootViewController: UIHostingController
            let searchController = UISearchController(searchResultsController: nil)
            var search: () -> Void
            var cancel: () -> Void
            
            init(content: Content, searchText: Binding, searchAction: @escaping () -> Void, cancelAction: @escaping () -> Void) {
                rootViewController = UIHostingController(rootView: content)
                searchController.searchBar.autocapitalizationType = .none
                searchController.obscuresBackgroundDuringPresentation = false
                rootViewController.navigationItem.searchController = searchController
                
                _text = searchText
                search = searchAction
                cancel = cancelAction
            }
            
            func update(content: Content) {
                rootViewController.rootView = content
                rootViewController.view.setNeedsDisplay()
            }
            
            func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
                text = searchText
            }
            
            func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
                search()
            }
            
            func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
                cancel()
            }
        }
        
    }
    

    The above code can be used as-is (and can of-course be modified to suit the specific needs of the project).

    The view includes actions for 'search' and 'cancel' which are respectively called when the search key is tapped on the keyboard and the cancel button of the search bar is pressed. The view also includes a SwiftUI view as a trailing closure and hence can directly replace the NavigationView.

    Usage (in SwiftUI View):

    import SwiftUI
    
    struct YourView: View {
        // Search string to use in the search bar
        @State var searchString = ""
        
        // Search action. Called when search key pressed on keyboard
        func search() {
        }
        
        // Cancel action. Called when cancel button of search bar pressed
        func cancel() {
        }
        
        // View body
        var body: some View {
            // Search Navigation. Can be used like a normal SwiftUI NavigationView.
            SearchNavigation(text: $searchString, search: search, cancel: cancel) {
                // Example SwiftUI View
                List(dataArray) { data in
                    Text(data.text)
                }
                .navigationBarTitle("Usage Example")
            }
            .edgesIgnoringSafeArea(.top)
        }
    }
    

    I have also written an article on this, it may be referred to get additional clarification.

    I hope this helps, cheers!

提交回复
热议问题