Cómo agregar una barra de búsqueda en SwiftUI
Libranner Santos
18 octubre, 20234min de lectura
Una barra de búsqueda puede mejorar la experiencia del usuario en nuestras aplicaciones al permitirles encontrar información rápidamente.
Gracias al modificador searchable
, podemos agregar una barra de búsqueda en SwiftUI. Veamos un ejemplo:
Preparando los datos
Primero, creamos la estructura que necesitaremos. En un nuevo proyecto de iOS con SwiftUI, abre ContentView.swift y coloca el siguiente código justo antes de la declaración de ContentView
:
struct Employee: Identifiable {let id = UUID()let name: Stringvar active: Bool = true}
Esta estructura contendrá los datos de los empleados que queremos filtrar.
Ahora, dentro de ContentView
y antes de la propiedad body
, agrega el siguiente código:
// 1private let employees = [Employee(name: "Angela"),Employee(name: "Pam", active: false),Employee(name: "Dwight"),Employee(name: "Jim", active: false),Employee(name: "Michael", active: false),Employee(name: "Oscar")]// 2@State private var criteria = ""
Este código realiza lo siguiente:
- Crea un arreglo de
Employee
que será nuestra fuente de datos. - Define una variable de estado que contendrá el criterio de búsqueda.
Preparando la vista
Dentro de body
, reemplaza el código existente con el siguiente:
NavigationStack {List {ForEach(filteredItems) { employee inText(employee.name)}}}.searchable(text: $criteria, prompt: "Employee name")
Con este código creamos un NavigationStack
que contiene un List
que mostrará todo los empleados contenidos en la variable filteredItems
. Además hemos agregado el modificador searchable(text:placement:prompt:)
que se encarga de incluir la barra de búsqueda al NavigationStack
.
Veras un error de compilación para corregirlo, agrega la variable filteredItems
. Esta es una variable calculada que retorna los empleados tomando en cuenta el valor de criteria
para filtrarlos:
var filteredItems: [Employee] {if criteria.isEmpty {return employees} else {return employees.filter { $0.name.localizedCaseInsensitiveContains(criteria)}}}
Si criteria
está vacía, este código retornará la lista completa; de lo contrario, filtrará los empleados según el valor de la propiedad name
.
Ejecuta el proyecto e introduce la letra A en la barra de búsqueda para ver la funcionalidad en acción.
Agregando Scopes
La barra de búsqueda puede complementarse utilizando searchScopes(_:scopes:)
. Con este modificador, podemos refinar el criterio de búsqueda al permitir que el usuario indique la categoría de búsqueda.
Justo debajo de la declaración de Employee
, agrega el siguiente enum
:
enum Scope: String, CaseIterable {case active, inactive}
Luego, debajo de la declaración de criteria
, agrega:
@State private var scope = Scope.active
Hemos añadido un enum
con las opciones que queremos mostrar y una variable de estado, scope
, para guardar los cambios según lo indique el usuario. scope
por defecto tiene el valor Scope.active
, por lo que la primera vez que se muestre la lista solo podremos visualizar los empleados activos.
Debajo de .searchable(text:placement:prompt:)
, agrega el siguiente código:
.searchScopes($scope) {ForEach(Scope.allCases, id: \.self) { scope inText(scope.rawValue.capitalized)}}
Este código agrega searchScopes(_:scopes:)
, que nos permite indicar la variable de estado que almacenará el scope deseado.
Para que esto funcione, debemos modificar filteredItems
para que tome en cuenta el valor de scope
:
var filteredItems: [Employee] {// 1let isActive = scope == .activeif criteria.isEmpty {// 2return employees.filter { $0.active == isActive }} else {// 3return employees.filter { $0.name.localizedCaseInsensitiveContains(criteria) && $0.active == isActive}}}
Este código realiza lo siguiente:
- Utiliza la variable
isActive
para almacenar un valor booleano que indica si estamos filtrando solo empleados activos. - Si
criteria
está vacío, filtra solo por la propiedad active. - En caso contrario, filtra por
name
yactive
.
Ejecuta la aplicación para ver la nueva funcionalidad en acción:
Otras cosas a tomar en cuenta
Si quisieras reaccionar cuando el usuario presiona la tecla search
del teclado puedes usar el modificador onSubmit(of:_:)
, por ejemplo:
.onSubmit(of: .search, filterEmployees)