SwiftUI es el framework de Apple que te permite construir interfaces visuales para iPhone usando estructuras de Swift declarativas y muy poco código.
Con SwiftUI describes qué quieres ver en pantalla, no cómo dibujarlo paso a paso. Eso hace que el código sea más corto y más fácil de leer.
Los bloques básicos de SwiftUI
SwiftUI tiene cuatro vistas que usarás en casi toda app:
| Vista | ¿Para qué sirve? |
|---|---|
Text |
Mostrar texto estático o dinámico |
Button |
Ejecutar una acción al tocar |
TextField |
Capturar texto del usuario |
VStack |
Apilar vistas una encima de otra |
Cada vista es una struct que conforma el protocolo View. Eso conecta directamente con la lección anterior: en SwiftUI, toda pantalla es una struct.
Estructura de una vista SwiftUI
Toda vista SwiftUI sigue este patrón:
struct NombreVista: View {
var body: some View {
// tus vistas aquí
}
}
La propiedad body devuelve exactamente una vista raíz. Si necesitas colocar varias vistas juntas, las envuelves en un contenedor como VStack.
Text — mostrar texto en pantalla
Text es la vista más simple. Recibe un String y lo muestra.
Text("Bienvenido a Liverpool")
Puedes encadenar modificadores para cambiar su apariencia:
Text("Oferta del día")
.font(.title)
.foregroundColor(.red)
.bold()
Cada modificador devuelve una nueva vista. No modifica la vista original: la envuelve. Por eso puedes encadenarlos sin límite.
Button — ejecutar acciones
Un Button tiene dos partes: la acción (qué hace) y la etiqueta (qué muestra).
Button(action: {
print("Producto agregado al carrito")
}) {
Text("Agregar al carrito")
}
También existe la sintaxis corta con trailing closure:
Button("Agregar al carrito") {
print("Producto agregado al carrito")
}
Las dos formas producen el mismo resultado. La segunda es más común en proyectos modernos.
TextField — capturar texto del usuario
TextField necesita dos cosas: un texto de sugerencia (placeholder) y una variable de estado donde guardar lo que escribe el usuario.
Para crear esa variable de estado usas el property wrapper @State:
struct BusquedaView: View {
@State private var nombreProducto: String = ""
var body: some View {
TextField("Busca un producto", text: $nombreProducto)
.textFieldStyle(.roundedBorder)
.padding()
}
}
@State le dice a SwiftUI que esta variable controla la pantalla. Cuando cambia, SwiftUI redibuja body automáticamente.
El símbolo $nombreProducto es un binding: conecta el TextField con la variable para que los cambios fluyan en los dos sentidos.
VStack — organizar vistas verticalmente
VStack apila sus hijos de arriba hacia abajo. Es el contenedor más usado en SwiftUI.
VStack {
Text("FEMSA — Tienda en línea")
Text("Selecciona tu producto")
Button("Ver catálogo") {
print("Mostrando catálogo")
}
}
Puedes controlar el espacio entre elementos con el parámetro spacing:
VStack(spacing: 16) {
Text("Bimbo")
Text("Pan de caja")
}
Otros contenedores útiles son HStack (horizontal) y ZStack (apilado con capas). En esta lección nos enfocamos en VStack porque cubre la mayoría de los casos básicos.
Ejemplo completo: pantalla de búsqueda de producto
Este ejemplo combina los cuatro elementos en una pantalla funcional al estilo Mercado Libre:
struct BusquedaProductoView: View {
@State private var busqueda: String = ""
@State private var resultado: String = "Aquí aparecerá el resultado"
var body: some View {
VStack(spacing: 20) {
Text("Mercado Libre MX")
.font(.largeTitle)
.bold()
TextField("¿Qué estás buscando?", text: $busqueda)
.textFieldStyle(.roundedBorder)
.padding(.horizontal)
Button("Buscar") {
if busqueda.isEmpty {
resultado = "Escribe un producto primero"
} else {
resultado = "Buscando: \(busqueda)"
}
}
.buttonStyle(.borderedProminent)
Text(resultado)
.foregroundColor(.secondary)
}
.padding()
}
}
Cuando el usuario escribe "Tenis" y toca "Buscar", el Text inferior muestra:
Buscando: Tenis
Si toca "Buscar" sin escribir nada, muestra:
Escribe un producto primero
Esta lógica condicional dentro del Button es suficiente para muchas pantallas reales.
Ejemplo avanzado: mini formulario de pedido
Este ejemplo simula la captura de un pedido en una app de logística para FEMSA:
struct FormularioPedidoView: View {
@State private var nombreCliente: String = ""
@State private var cantidadCajas: String = ""
@State private var confirmacion: String = ""
var body: some View {
VStack(spacing: 18) {
Text("Nuevo Pedido")
.font(.title2)
.bold()
TextField("Nombre del cliente", text: $nombreCliente)
.textFieldStyle(.roundedBorder)
TextField("Número de cajas", text: $cantidadCajas)
.textFieldStyle(.roundedBorder)
.keyboardType(.numberPad)
Button("Registrar pedido") {
let cajas = Int(cantidadCajas) ?? 0
let precioPorCaja = 350
let total = cajas * precioPorCaja
confirmacion = "Pedido de \(nombreCliente): $\(total)"
}
.buttonStyle(.borderedProminent)
Text(confirmacion)
.multilineTextAlignment(.center)
.padding()
}
.padding()
}
}
Si el usuario escribe "Distribuidora del Norte" y "40 cajas", el resultado es:
Pedido de Distribuidora del Norte: $14,000
El modificador .keyboardType(.numberPad) abre el teclado numérico automáticamente en iPhone. Es un detalle pequeño que mejora mucho la experiencia del usuario.
Errores comunes
Error 1 — Olvidar @State en variables que cambian
Si declaras una variable sin @State, SwiftUI no sabe que debe redibujar la pantalla cuando cambie.
// ❌ Incorrecto
var nombre: String = ""
// ✅ Correcto
@State private var nombre: String = ""
El error más común es que escribes en el TextField y la pantalla nunca se actualiza. La causa es casi siempre un @State faltante.
Error 2 — Usar nombreProducto en lugar de $nombreProducto en el TextField
Sin el signo $, pasas el valor actual, no el binding. El TextField no podrá escribir de regreso a tu variable.
// ❌ Incorrecto
TextField("Busca", text: nombreProducto)
// ✅ Correcto
TextField("Busca", text: $nombreProducto)
Xcode te mostrará un error de compilación claro en este caso. Aprende a leerlo: casi siempre dice "cannot convert value of type 'String' to expected argument type 'Binding
Error 3 — Poner más de una vista raíz en body sin contenedor
body solo acepta una vista. Si pones dos Text sin envolverlos en VStack, el compilador falla.
// ❌ Incorrecto
var body: some View {
Text("Línea 1")
Text("Línea 2")
}
// ✅ Correcto
var body: some View {
VStack {
Text("Línea 1")
Text("Línea 2")
}
}
Referencia rápida de modificadores útiles
| Modificador | Efecto |
|---|---|
.font(.title) |
Cambia el tamaño de fuente |
.bold() |
Pone el texto en negritas |
.foregroundColor(.red) |
Cambia el color del texto |
.padding() |
Agrega espacio alrededor |
.padding(.horizontal) |
Espacio solo a los lados |
.buttonStyle(.borderedProminent) |
Botón con fondo de color |
.textFieldStyle(.roundedBorder) |
Campo con borde redondeado |
.keyboardType(.numberPad) |
Abre teclado numérico |
.multilineTextAlignment(.center) |
Centra texto de varias líneas |
Puntos clave
- SwiftUI es declarativo: describes qué mostrar, no cómo dibujarlo.
@Statemarca las variables que controlan la pantalla. Sin él, los cambios no se reflejan visualmente.- El binding
$variableconecta unTextFieldcon su variable de estado en los dos sentidos. VStackes el contenedor principal para apilar vistas verticalmente. Aceptaspacingpara controlar la separación.- Los modificadores se encadenan después de cualquier vista y transforman su apariencia sin modificar la vista original.