[SUI] Barra de búsqueda
Source: Dev.to
Barra de búsqueda en NavigationStack
Un NavigationStack puede incluir una barra de búsqueda mediante el modificador searchable.
Su firma es:
searchable(
text: Binding,
tokens: Binding? = nil,
suggestedTokens: [Token]? = nil,
placement: SearchFieldPlacement = .automatic,
prompt: String? = nil,
token: () -> TokenView? = { nil }
)
- text: texto introducido por el usuario.
- tokens: seguimiento de los tokens mostrados.
- suggestedTokens: lista de tokens sugeridos.
- placement: ubicación de la barra (
automatic,navigationBarDrawer,sidebar,toolbar, etc.). - prompt: placeholder.
- token: vista para mostrar los tokens.
Uso básico
struct Person: Identifiable {
let id = UUID()
let name: String
}
private let people: [Person] = [
.init(name: "David Goyes"),
.init(name: "Midoriya Izuku"),
.init(name: "Tanjiro Kamado"),
.init(name: "David Beckham"),
]
struct ContentView: View {
@State private var searchText: String = ""
private var filteredPeople: [Person] {
if searchText.isEmpty {
people
} else {
people.filter { $0.name.localizedStandardContains(searchText) }
}
}
var body: some View {
NavigationStack {
List(filteredPeople) { person in
Text(person.name)
}
.navigationTitle("Personas")
.searchable(text: $searchText, prompt: "¿A quién busca?")
}
}
}
En iOS 26, por defecto la barra se coloca en la parte inferior (equivalente a
toolbar). Cuando se vuelve el first responder, aparece encima del teclado.
Actualizando la lista con onChange
Si se prefiere almacenar el resultado filtrado, es necesario actualizarlo manualmente:
struct ContentView: View {
@State private var searchText: String = ""
@State private var filteredPeople: [Person] = []
var body: some View {
NavigationStack {
List(filteredPeople) { person in
Text(person.name)
}
.navigationTitle("Personas")
.searchable(text: $searchText, prompt: "¿A quién busca?")
.onChange(of: searchText, initial: true) {
filterPeople()
}
}
}
private func filterPeople() {
filteredPeople = searchText.isEmpty
? people
: people.filter { $0.name.localizedStandardContains(searchText) }
}
}
Ubicaciones de la barra de búsqueda
automatic/toolbar: siempre visible en la barra inferior.navigationBarDrawer: desaparece al desplazar la lista hacia arriba y reaparece al desplazarse hacia abajo.
Para mantenerla siempre visible en la barra de navegación:
struct ContentView: View {
@State private var searchText: String = ""
private var filteredPeople: [Person] {
if searchText.isEmpty {
people
} else {
people.filter { $0.name.localizedStandardContains(searchText) }
}
}
var body: some View {
NavigationStack {
List(filteredPeople) { person in
Text(person.name)
}
.navigationTitle("Personas")
.searchable(
text: $searchText,
placement: .navigationBarDrawer(displayMode: .always),
prompt: "¿A quién busca?"
)
}
}
}
Enfoque programático con searchFocused
Se puede controlar el foco de la barra mediante searchFocused(_:) y un @FocusState:
struct ContentView: View {
@State private var searchText: String = ""
@FocusState private var isFocused: Bool // <-- foco de la barra
private var filteredPeople: [Person] {
if searchText.isEmpty {
people
} else {
people.filter { $0.name.localizedStandardContains(searchText) }
}
}
var body: some View {
NavigationStack {
List(filteredPeople) { person in
Text(person.name)
}
.navigationTitle("Personas")
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Buscar", systemImage: "magnifyingglass") {
isFocused = true // enfoca la barra
}
}
}
.searchable(
text: $searchText,
placement: .navigationBarDrawer(displayMode: .automatic),
prompt: "¿A quién busca?"
)
.searchFocused($isFocused) // controla el foco
}
}
}
El botón “Buscar” del toolbar establece isFocused en true, lo que muestra el teclado y coloca el cursor en la barra de búsqueda.