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í
y cuando la barra de búsqueda se edita así:
En acción:
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!