En el desarrollo de aplicaciones móviles modernas, el espacio en pantalla es el activo más valioso. La interfaz de usuario debe ser limpia, intuitiva y, sobre todo, funcional. Aquí es donde entra en juego la Toolbar (Barra de Herramientas). Ya no se trata solo de esa barra en la parte superior donde vive el título; en SwiftUI, la Toolbar es un sistema de gestión de acciones inteligente y semántico que se adapta a iOS, iPadOS, macOS y watchOS.
Si vienes de UIKit, recordarás los días de configurar navigationItem.rightBarButtonItem y lidiar con el ciclo de vida del controlador. SwiftUI cambia el juego con el modificador declarativo .toolbar.
En este tutorial exhaustivo de 2000 palabras, vamos a diseccionar cómo añadir botones, gestionar su ubicación, controlar su estado y estilizar la barra de herramientas en Xcode para crear experiencias de usuario de primer nivel.
1. El Fundamento: NavigationStack
Antes de poder colocar un solo botón, necesitamos un contexto. Las barras de herramientas en SwiftUI no flotan en el vacío; generalmente viven dentro de una estructura de navegación.
Hasta iOS 15 usábamos NavigationView, pero el estándar moderno (y el que debes usar en 2025) es NavigationStack. Este contenedor proporciona el “lienzo” superior (la barra de navegación) y la capacidad de apilar vistas.
Configuración Inicial del Proyecto
Abre Xcode y crea un nuevo proyecto SwiftUI. En tu ContentView.swift, establece la estructura base:
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationStack {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Bienvenido al Tutorial de Toolbar")
}
.navigationTitle("Inicio")
.navigationBarTitleDisplayMode(.large)
}
}
}Al ejecutar esto, verás una barra de navegación vacía con el título “Inicio”. Ahora estamos listos para poblarla.
2. Anatomía del Modificador .toolbar
El modificador .toolbar se aplica a la vista dentro del stack de navegación, no al stack en sí. Esto es crucial: la toolbar pertenece al contenido, no al contenedor.
Para añadir un botón, utilizamos la estructura ToolbarItem.
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("Guardar") {
print("Acción de guardar ejecutada")
}
}
}¿Por qué ToolbarItem?
Podrías simplemente lanzar un Button dentro de .toolbar y a veces funcionaría, pero ToolbarItem te da control explícito sobre el placement (ubicación). SwiftUI utiliza un sistema semántico para determinar dónde colocar los elementos.
3. Dominando las Ubicaciones (ToolbarItemPlacement)
El parámetro placement es donde ocurre la magia. En lugar de pensar en píxeles (x, y), pensamos en roles. Veamos las opciones más importantes y cuándo usarlas.
A. .topBarTrailing y .topBarLeading (La Cima)
Estas son las ubicaciones estándar en la barra de navegación superior.
.topBarLeading: El borde inicial (Izquierda en idiomas LTR). Ideal para botones de “Cancelar”, “Cerrar” o menús laterales (Hamburger menu)..topBarTrailing: El borde final (Derecha en idiomas LTR). Ideal para la acción principal de la pantalla: “Guardar”, “Editar”, “Añadir”.
Nota de compatibilidad: Si soportas versiones anteriores a iOS 17, verás
navigationBarLeadingynavigationBarTrailing. Apple los ha renombrado atopBar...para generalizar su uso, pero el comportamiento es idéntico.
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Cancelar", role: .cancel) { }
}
ToolbarItem(placement: .topBarTrailing) {
Button(action: saveDocument) {
Label("Guardar", systemImage: "square.and.arrow.down")
}
}
}B. .principal (El Centro de Atención)
Por defecto, el centro de la barra de navegación muestra el navigationTitle. Sin embargo, a veces necesitas algo más complejo: un logotipo de marca, un selector de fecha o un Picker (segment control).
El placement .principal reemplaza el título estándar con tu vista personalizada.
ToolbarItem(placement: .principal) {
VStack {
Text("Documento 1").font(.headline)
Text("Editado hace 5 min").font(.caption2).foregroundStyle(.secondary)
}
}C. .bottomBar (La Barra Inferior)
Muchos desarrolladores olvidan que SwiftUI puede generar automáticamente una barra de herramientas inferior (similar a la de Safari en iOS) simplemente cambiando el placement. Esto es útil para mover acciones secundarias y dejar la parte superior limpia.
ToolbarItem(placement: .bottomBar) {
HStack {
Button(action: {}) { Image(systemName: "chevron.left") }
Spacer() // Empuja los botones a los extremos
Button(action: {}) { Image(systemName: "square.and.arrow.up") }
}
}D. .keyboard (El Truco de Productividad)
Este es, quizás, el placement más útil para formularios. Permite añadir botones directamente sobre el teclado virtual del sistema. Es perfecto para añadir un botón “Listo” (Done) en teclados numéricos que no tienen tecla de retorno.
ToolbarItem(placement: .keyboard) {
HStack {
Spacer()
Button("Listo") {
// Código para cerrar el teclado
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
}4. Agrupando Botones: ToolbarItemGroup
Imagina que necesitas tres botones a la derecha: “Buscar”, “Filtrar” y “Perfil”. Si escribes tres ToolbarItem con el mismo placement .topBarTrailing, funcionará, pero el código será repetitivo.
Para esto existe ToolbarItemGroup. Agrupa múltiples vistas bajo una misma ubicación y deja que SwiftUI gestione el espaciado (padding) entre ellas.
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button(action: {}) { Image(systemName: "magnifyingglass") }
Button(action: {}) { Image(systemName: "slider.horizontal.3") }
Link(destination: URL(string: "https://apple.com")!) {
Image(systemName: "person.circle")
}
}
}Consejo de Diseño: Evita saturar la barra superior. Si tienes más de 2 o 3 acciones principales, considera moverlas a un menú contextual o a la barra inferior.
5. Diseño y Estilizado de Botones
Los botones en la toolbar no tienen por qué ser simples textos azules. SwiftUI nos da herramientas para estilizarlos y hacerlos más accesibles.
Uso de Label para Accesibilidad
En lugar de usar Image(systemName: "plus"), acostúmbrate a usar Label("Añadir", systemImage: "plus"). En la toolbar, SwiftUI mostrará solo el icono automáticamente para ahorrar espacio, pero VoiceOver leerá el texto “Añadir”. Es una ganancia de accesibilidad gratuita.
Cambiando el Color (.tint)
Puedes cambiar el color de los botones usando el modificador .tint.
Button("Borrar") { ... }
.tint(.red)Botones Prominentes
A veces quieres que la acción principal destaque visualmente, por ejemplo, un botón con fondo de color (“capsule”). Desde iOS 16, podemos aplicar estilos de botón dentro de la toolbar.
ToolbarItem(placement: .topBarTrailing) {
Button("Comprar") { }
.buttonStyle(.borderedProminent)
.tint(.green)
.clipShape(Capsule())
}Nota: Úsalo con moderación. Un botón con borde en la barra de navegación llama mucho la atención.
6. Lógica de Estado: Habilitar y Deshabilitar Botones
Una toolbar estática es aburrida. Queremos que reaccione a lo que hace el usuario. Por ejemplo, el botón “Guardar” debería estar deshabilitado si el formulario está vacío.
struct FormularioView: View {
@State private var nombre: String = ""
@State private var guardando: Bool = false
var body: some View {
NavigationStack {
Form {
TextField("Nombre del producto", text: $nombre)
}
.navigationTitle("Nuevo Producto")
.toolbar {
ToolbarItem(placement: .confirmationAction) {
if guardando {
ProgressView()
} else {
Button("Guardar") {
simularGuardado()
}
.disabled(nombre.isEmpty) // Deshabilitado si no hay texto
}
}
}
}
}
func simularGuardado() {
guardando = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
guardando = false
nombre = ""
}
}
}En este ejemplo, usamos .confirmationAction (un alias semántico para la acción positiva a la derecha) y conectamos el modificador .disabled a nuestra variable de estado. También reemplazamos dinámicamente el botón por un ProgressViewmientras se realiza la acción.
7. Menús Desplegables en la Toolbar
Cuando el espacio es limitado, el componente Menu es tu mejor amigo. Permite agrupar acciones secundarias bajo un solo botón.
ToolbarItem(placement: .topBarTrailing) {
Menu {
Button("Duplicar", systemImage: "plus.square.on.square") { }
Button("Renombrar", systemImage: "pencil") { }
Divider()
Button("Eliminar", systemImage: "trash", role: .destructive) { }
} label: {
Label("Opciones", systemImage: "ellipsis.circle")
}
}Esto despliega un menú nativo de iOS elegante y funcional, manteniendo tu interfaz limpia.
8. Personalización del Fondo de la Toolbar
Hasta hace poco, cambiar el color de fondo de la barra de navegación en SwiftUI era una pesadilla que requieria hacks de UIKit (UINavigationBar.appearance). Ahora, tenemos una API nativa: .toolbarBackground.
Visibilidad y Color
Por defecto, la barra es transparente y se vuelve translúcida al hacer scroll. Para forzar un color corporativo:
.toolbarBackground(Color.indigo, for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.toolbarColorScheme(.dark, for: .navigationBar)- Color: Define el fondo (puede ser un
Color,GradientoMaterial). - Visible: Fuerza que la barra se vea sólida incluso sin hacer scroll.
- ColorScheme:
.darkindica que el fondo es oscuro, por lo que SwiftUI pintará el texto y los botones de color blanco.
9. Ejemplo Completo: El Editor de Notas
Vamos a combinar todo lo aprendido en una pantalla realista. Imagina una app de notas donde podemos escribir, ver el recuento de caracteres y tener acciones de formato.
import SwiftUI
struct EditorNotasView: View {
@State private var texto: String = "Escribe tu próxima gran idea..."
@State private var esFavorito: Bool = false
@FocusState private var focoTeclado: Bool
var body: some View {
NavigationStack {
TextEditor(text: $texto)
.padding()
.focused($focoTeclado)
.navigationTitle("Nota Rápida")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
// 1. Grupo a la izquierda: Cerrar teclado
ToolbarItem(placement: .topBarLeading) {
if focoTeclado {
Button("Hecho") {
focoTeclado = false
}
}
}
// 2. Grupo a la derecha: Favorito y Compartir
ToolbarItemGroup(placement: .topBarTrailing) {
Button {
withAnimation { esFavorito.toggle() }
} label: {
Image(systemName: esFavorito ? "star.fill" : "star")
.foregroundStyle(esFavorito ? .yellow : .primary)
.symbolEffect(.bounce, value: esFavorito) // Animación iOS 17
}
ShareLink(item: texto) {
Image(systemName: "square.and.arrow.up")
}
}
// 3. Barra inferior: Contador de caracteres
ToolbarItem(placement: .bottomBar) {
HStack {
Text("\(texto.count) caracteres")
.font(.caption)
.foregroundStyle(.secondary)
Spacer()
Text("Última edición: Hoy")
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
}
}
}Desglose del Ejemplo Pro:
- Reactividad: El botón “Hecho” a la izquierda solo aparece si el teclado está activo (
focoTeclado). - Feedback Visual: El botón de estrella cambia de icono (
fillvsoutline) y de color. Además, usamos.symbolEffect(nuevo en iOS 17) para darle un rebote animado al pulsarlo. - ShareLink: Usamos un componente nativo de SwiftUI dentro de la toolbar para compartir el texto.
- Barra Inferior Informativa: Usamos el espacio inferior para metadatos, equilibrando la interfaz.
Conclusión
La gestión de botones en la Toolbar de SwiftUI ha evolucionado para ser una herramienta increíblemente potente y flexible. Ya no se trata de colocar vistas en coordenadas; se trata de definir intenciones semánticas y dejar que el sistema optimice la experiencia para el usuario.
Recuerda los pilares clave:
- Usa siempre
ToolbarItemcon elplacementcorrecto. - Agrupa acciones relacionadas con
ToolbarItemGroupoMenu. - No olvides la accesibilidad usando
Label. - Aprovecha la
.bottomBary la barra de.keyboardpara mejorar la ergonomía.
Con estas técnicas en tu arsenal, estás listo para crear interfaces de usuario profesionales, limpias y nativas que encantarán a tus usuarios.
Si tienes cualquier duda sobre este artículo, contacta conmigo y estaré encantado de ayudarte 🙂. Puedes contactar conmigo en mi perfil de X o en mi perfil de Instagram










