Saltar al contenido

Cómo mostrar una barra de búsqueda con SwiftUI

Si encuentras alguna parte que no entiendes nos puedes dejar un comentario y te ayudaremos rápidamente.

Solución:

Aquí hay una versión pura de swiftUI, basada en la respuesta de Antoine Weber a su pregunta anterior y lo que encontré en este blog y esta esencia. Incorpora

  • un botón claro,
  • un botón de cancelar,
  • renunciando al teclado al arrastrar en la lista y
  • ocultar la vista de navegación cuando se selecciona el campo de texto de búsqueda.

La renuncia al teclado al arrastrar en la lista se puede realizar utilizando un método en la ventana de la aplicación UIA siguiendo estas respuestas. Para un manejo más fácil, creé una extensión en UIApplication y modificador de vista para esta extensión y finalmente una extensión para Ver:

extension UIApplication 
    func endEditing(_ force: Bool) 
        self.windows
            .filter$0.isKeyWindow
            .first?
            .endEditing(force)
    


struct ResignKeyboardOnDragGesture: ViewModifier 
    var gesture = DragGesture().onChanged_ in
        UIApplication.shared.endEditing(true)
    
    func body(content: Content) -> some View 
        content.gesture(gesture)
    


extension View 
    func resignKeyboardOnDragGesture() -> some View 
        return modifier(ResignKeyboardOnDragGesture())
    

Entonces, el modificador final para renunciar al teclado es solo un modificador que debe colocarse en la lista de esta manera:

List 
    ForEach(...) 
        //...
    

.resignKeyboardOnDragGesture()

El código completo del proyecto swiftUI para la barra de búsqueda con una lista de nombres de muestra es el siguiente. Puede pegarlo en ContentView.swift de un nuevo proyecto swiftUI y jugar con él.


import SwiftUI

struct ContentView: View 
    let array = ["Peter", "Paul", "Mary", "Anna-Lena", "George", "John", "Greg", "Thomas", "Robert", "Bernie", "Mike", "Benno", "Hugo", "Miles", "Michael", "Mikel", "Tim", "Tom", "Lottie", "Lorrie", "Barbara"]
    @State private var searchText = ""
    @State private var showCancelButton: Bool = false

    var body: some View 

        NavigationView 
            VStack 
                // Search view
                HStack 
                    HStack 
                        Image(systemName: "magnifyingglass")

                        TextField("search", text: $searchText, onEditingChanged:  isEditing in
                            self.showCancelButton = true
                        , onCommit: 
                            print("onCommit")
                        ).foregroundColor(.primary)

                        Button(action: 
                            self.searchText = ""
                        ) 
                            Image(systemName: "xmark.circle.fill").opacity(searchText == "" ? 0 : 1)
                        
                    
                    .padding(EdgeInsets(top: 8, leading: 6, bottom: 8, trailing: 6))
                    .foregroundColor(.secondary)
                    .background(Color(.secondarySystemBackground))
                    .cornerRadius(10.0)

                    if showCancelButton  
                        Button("Cancel") 
                                UIApplication.shared.endEditing(true) // this must be placed before the other commands here
                                self.searchText = ""
                                self.showCancelButton = false
                        
                        .foregroundColor(Color(.systemBlue))
                    
                
                .padding(.horizontal)
                .navigationBarHidden(showCancelButton) // .animation(.default) // animation does not work properly

                List 
                    // Filtered list of names
                    ForEach(array.filter, id:.self) 
                        searchText in Text(searchText)
                    
                
                .navigationBarTitle(Text("Search"))
                .resignKeyboardOnDragGesture()
            
        
    




struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        Group 
           ContentView()
              .environment(.colorScheme, .light)

           ContentView()
              .environment(.colorScheme, .dark)
        
    


extension UIApplication 
    func endEditing(_ force: Bool) 
        self.windows
            .filter$0.isKeyWindow
            .first?
            .endEditing(force)
    


struct ResignKeyboardOnDragGesture: ViewModifier 
    var gesture = DragGesture().onChanged_ in
        UIApplication.shared.endEditing(true)
    
    func body(content: Content) -> some View 
        content.gesture(gesture)
    


extension View 
    func resignKeyboardOnDragGesture() -> some View 
        return modifier(ResignKeyboardOnDragGesture())
    

El resultado final de la barra de búsqueda, cuando se muestra inicialmente, se ve así

ingrese la descripción de la imagen aquí

y cuando la barra de búsqueda se edita así:

ingrese la descripción de la imagen aquí

En acción:

ingrese la descripción de la imagen aquí

Este video de YouTube muestra cómo se puede hacer. Se reduce a:

struct SearchBar: UIViewRepresentable 

    @Binding var text: String

    class Coordinator: NSObject, UISearchBarDelegate 

        @Binding var text: String

        init(text: Binding) 
            _text = text
        

        func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) 
            text = searchText
        
    
    func makeCoordinator() -> SearchBar.Coordinator 
        return Coordinator(text: $text)
    

    func makeUIView(context: UIViewRepresentableContext) -> UISearchBar 
        let searchBar = UISearchBar(frame: .zero)
        searchBar.delegate = context.coordinator
        searchBar.autocapitalizationType = .none
        return searchBar
    

    func updateUIView(_ uiView: UISearchBar, context: UIViewRepresentableContext) 
        uiView.text = text
    

y luego en lugar de

TextField($searchText)
              .textFieldStyle(.roundedBorder)

tu usas

SearchBar(text: $searchText)

Una barra de búsqueda nativa se puede implementar correctamente en SwiftUI envolviendo el UINavigationController.

Este enfoque nos da la ventaja de lograr todos los comportamientos esperados, incluido ocultar / mostrar automáticamente al desplazarse, borrar y cancelar, y buscar. key en el teclado entre otros.

Envolver el UINavigationController para la barra de búsqueda también asegura que cualquier cambio nuevo realizado por Apple se adopte automáticamente en su proyecto.

Salida de ejemplo

Haga clic aquí para ver la implementación en acción

Código (ajuste 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()
        
    
    

El código anterior se puede utilizar tal cual (y, por supuesto, se puede modificar para adaptarse a las necesidades específicas del proyecto).

La vista incluye acciones para ‘buscar’ y ‘cancelar’ que se llaman respectivamente cuando la búsqueda key se presiona en el teclado y se presiona el botón cancelar de la barra de búsqueda. La vista también incluye una vista SwiftUI como cierre final y, por lo tanto, puede reemplazar directamente NavigationView.

Uso (en 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)
    

También he escrito un artículo sobre esto, puede ser referido para obtener aclaraciones adicionales.

Espero que esto ayude, ¡salud!

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags : /

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *