Text en SwiftUI: Tu Primera Vista de Texto (¡Y la más importante!)

¿Listo para dominar el componente más usado en SwiftUI? Sí, hablo de `Text`. Ese pequeño gran héroe que está en TODAS las apps. Si estás empezando con SwiftUI, este es tu artículo. Y si ya llevas un tiempo... te prometo que aprenderás algún truco nuevo 😉 ## ¿Por qué Text es tan especial? Imagínate esto: estás creando tu primera app en SwiftUI. ¿Cuál es la primera línea de código que escribes después del `ContentView`? Exacto: ```swift Text("¡Hola, mundo!") ``` ![Captura del preview de Xcode mostrando "¡Hola, mundo!" centrado](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752432476260-1.webp?alt=media&token=0ef67cda-93ad-4ebd-934e-2eea188b9cb3) Parece simple, ¿verdad? Pero aquí viene lo bueno: Text en SwiftUI no es solo un label aburrido como en los viejos tiempos de UIKit. Es una vista inteligente que: - 🌍 Se traduce sola (¡en serio!) - 📱 Se adapta al tamaño de letra que el usuario prefiere - 🎨 Se puede estilizar de mil formas - 🔗 Se puede combinar como piezas de LEGO ## Tu primer Text: Más fácil imposible Vale, empecemos por lo básico. Abre Xcode, crea un nuevo proyecto de SwiftUI y vamos a jugar: ```swift import SwiftUI struct ContentView: View { var body: some View { Text("¡Mi primera app en SwiftUI!") } } ``` ¡BAM! Ya tienes texto en pantalla. Sin IBOutlets, sin storyboards, sin dolor de cabeza. ### El truco del millón: Text es inmutable Aquí viene algo importante (agárrate): Text en SwiftUI es inmutable. ¿Qué significa eso? Que una vez creado, no puedes cambiar su contenido. "¿Cómo?", dirás. "¿Entonces cómo actualizo el texto?" ¡Fácil! SwiftUI recrea la vista cuando los datos cambian: ```swift struct ContadorView: View { @State private var contador = 0 // La magia está aquí var body: some View { VStack { Text("Has tocado \(contador) veces") Button("¡Tócame!") { contador += 1 // SwiftUI actualiza el Text automáticamente } } } } ``` ![GIF mostrando el contador incrementándose al tocar el botón](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433080761-2.gif?alt=media&token=af768345-0217-40b3-b457-1b5bc5e284e5) ## Los 3 constructores que DEBES conocer ### 1. El Constructor Básico (tu mejor amigo) ```swift Text("Este texto aparece tal cual") ``` Úsalo para texto estático que no cambia. Perfecto para títulos, etiquetas, instrucciones... ### 2. El Constructor con Variables ```swift struct PerfilView: View { let nombreUsuario = "Carlos" let edad = 28 var body: some View { VStack { Text(nombreUsuario) // Muestra: Carlos Text("Tienes \(edad) años") // Muestra: Tienes 28 años } } } ``` ### 3. El Constructor Verbatim (el rebelde) Este es especial. Le dice a SwiftUI: "Oye, muestra esto EXACTAMENTE como lo escribo": ```swift Text(verbatim: "usuario@ejemplo.com") // No intenta traducirlo ``` ¿Cuándo usarlo? Para emails, códigos, o cualquier texto que no debe ser procesado. ## Dale estilo a tu Text (¡Aquí empieza lo divertido!) ### Los modificadores básicos que cambiarán tu vida ```swift struct EstilosBasicos: View { var body: some View { VStack(spacing: 20) { Text("Soy NEGRITA") .bold() Text("Soy elegante") .italic() Text("Estoy subrayado") .underline() Text("Estoy tachado") .strikethrough() // ¡Y ahora... la combinación! Text("Soy negrita Y cursiva") .bold() .italic() .foregroundColor(.blue) } } } ``` ![Captura mostrando todos los estilos de texto aplicados](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433240035-3.webp?alt=media&token=9a8713ca-0f48-484a-be96-bdc3b8af7bf4) ### El peso importa (en las fuentes, claro) ¿Quieres control total sobre qué tan gruesa es tu fuente? SwiftUI te da 9 opciones: ```swift VStack { Text("Ultra Light").fontWeight(.ultraLight) Text("Light").fontWeight(.light) Text("Regular").fontWeight(.regular) Text("Medium").fontWeight(.medium) Text("Semibold").fontWeight(.semibold) Text("Bold").fontWeight(.bold) Text("Heavy").fontWeight(.heavy) Text("Black").fontWeight(.black) } ``` ### Ejemplo del mundo real: La tarjeta de producto Vamos a crear algo que verías en cualquier app de e-commerce: ```swift struct TarjetaProducto: View { let producto = "AirPods Pro" let precioOriginal = 279.99 let precioOferta = 199.99 let enOferta = true var body: some View { VStack(alignment: .leading, spacing: 8) { Text(producto) .font(.headline) .bold() if enOferta { // Precio tachado Text("$\(Int(precioOriginal))") .strikethrough() .foregroundColor(.gray) // Precio en oferta Text("$\(Int(precioOferta))") .font(.title2) .bold() .foregroundColor(.green) // Badge de descuento Text("¡Ahorra 29%!") .font(.caption) .bold() .foregroundColor(.white) .padding(.horizontal, 8) .padding(.vertical, 4) .background(Color.red) .cornerRadius(4) } } .padding() .background(Color.gray.opacity(0.1)) .cornerRadius(10) } } ``` ![Captura de la tarjeta de producto con el precio tachado y la oferta](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433270937-4.webp?alt=media&token=50db00e0-5beb-416f-9c0b-01101a67ec36) ## El Sistema de Fuentes de Apple (¡Úsalo o te arrepentirás!) Apple no diseñó estas fuentes por casualidad. Cada una tiene un propósito: ```swift struct JerarquiaVisual: View { var body: some View { VStack(alignment: .leading, spacing: 15) { Text("Large Title") .font(.largeTitle) // Para títulos principales Text("Title") .font(.title) // Secciones importantes Text("Headline") .font(.headline) // Encabezados de contenido Text("Body") .font(.body) // El texto normal Text("Caption") .font(.caption) // Texto secundario pequeño } } } ``` ![Comparación lado a lado de una app con fuentes del sistema vs tamaños fijos cuando se activa el texto grande](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433541775-9.webp?alt=media&token=19d8ef8d-85a3-46fb-9357-f35de4ba5cfb) ### ¿Por qué importa esto? Porque estas fuentes se adaptan AUTOMÁTICAMENTE cuando el usuario cambia el tamaño de texto en Ajustes. Si usas `.font(.system(size: 17))`, pierdes esa magia. ### Pro tip: Los diseños especiales ```swift VStack(spacing: 20) { Text("1234.56") .font(.largeTitle.monospaced()) // Números que no bailan Text("Diseño moderno") .font(.title.rounded()) // Esquinas suaves, muy iOS Text("Diseño clásico") .font(.title.serif()) // Para apps más formales } ``` ## Colores: Dale vida a tu texto ### Los básicos (pero no tan básicos) ```swift VStack(spacing: 15) { Text("Soy azul").foregroundColor(.blue) Text("Soy rojo").foregroundColor(.red) Text("Soy verde").foregroundColor(.green) // Pero espera... ¡hay más! } ``` ### Los colores inteligentes (esto es ORO) Estos colores se adaptan automáticamente al modo claro/oscuro: ```swift VStack(spacing: 15) { Text("Color principal") .foregroundColor(.primary) // Negro en claro, blanco en oscuro Text("Color secundario") .foregroundColor(.secondary) // Gris en ambos modos Text("Color de acento") .foregroundColor(.accentColor) // El color de tu app } ``` ![El mismo texto en modo claro y oscuro mostrando cómo se adaptan los colores](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433291717-5.webp?alt=media&token=f47073d8-7cf5-4fd3-8977-8f4b7843f6b8) ### Ejemplo brutal: Estados visuales ```swift struct EstadoTarea: View { enum Estado { case pendiente, enProgreso, completada var color: Color { switch self { case .pendiente: return .gray case .enProgreso: return .orange case .completada: return .green } } var emoji: String { switch self { case .pendiente: return "⏳" case .enProgreso: return "🔄" case .completada: return "✅" } } } let tareas: [(String, Estado)] = [ ("Aprender SwiftUI", .completada), ("Crear mi primera app", .enProgreso), ("Publicar en App Store", .pendiente) ] var body: some View { VStack(alignment: .leading, spacing: 15) { ForEach(tareas, id: \.0) { tarea in HStack { Text(tarea.1.emoji) Text(tarea.0) Spacer() Text(String(describing: tarea.1)) .font(.caption) .bold() .foregroundColor(.white) .padding(.horizontal, 12) .padding(.vertical, 4) .background(tarea.1.color) .cornerRadius(20) } } } .padding() } } ``` ## Control de líneas (cuando el texto se vuelve rebelde) ### El problema: texto que no cabe ```swift struct ProblemaTextoLargo: View { let descripcion = "Esta es una descripción súper larga que probablemente no quepa en una sola línea y necesitamos controlar cómo se muestra para que no rompa nuestro hermoso diseño" var body: some View { VStack(spacing: 30) { // Sin control (caos total) Text(descripcion) .border(Color.red) // Con límite de 2 líneas Text(descripcion) .lineLimit(2) .border(Color.green) // Truco ninja: truncar en el medio Text("documento_super_importante_version_final_final_de_verdad.pdf") .lineLimit(1) .truncationMode(.middle) // Muestra: documento_super...verdad.pdf .border(Color.blue) } .padding() } } ``` ![Los tres ejemplos de truncamiento mostrando las diferencias](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433315843-6.webp?alt=media&token=06c587cd-e1ca-43b7-ab07-9e2c3f4dcaf4) ## Los 5 errores de novato (y cómo evitarlos) ### Error #1: El texto que no se actualiza ```swift // ❌ MAL (no funcionará) struct VistaRota: View { var clicks = 0 // Sin @State = Sin actualizaciones var body: some View { Button("Clicks: \(clicks)") { clicks += 1 // Error: Cannot assign to property } } } // ✅ BIEN struct VistaFeliz: View { @State private var clicks = 0 // La magia de @State var body: some View { Button("Clicks: \(clicks)") { clicks += 1 // ¡Funciona! } } } ``` ### Error #2: El orden de los modificadores SÍ importa ```swift // ❌ El padding queda fuera del fondo Text("Hola") .background(Color.blue) .padding() // ✅ El fondo incluye el padding Text("Hola") .padding() .background(Color.blue) ``` ![Comparación visual del orden de modificadores](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433386247-7.webp?alt=media&token=88206e35-7c21-4094-8482-084aa93eeaef) ### Error #3: Colores invisibles en modo oscuro ```swift // ❌ Invisible en algunos modos Text("Importante") .foregroundColor(.white) // ✅ Se adapta automáticamente Text("Importante") .foregroundColor(.primary) ``` ### Error #4: No pensar en otros idiomas ```swift // ❌ Se rompe con textos largos HStack { Text("Precio:") Text("$99") } // ✅ Flexible para cualquier idioma Text("Precio: $99") // Una sola cadena localizable ``` ### Error #5: Abusar de tamaños fijos ```swift // ❌ No respeta las preferencias del usuario Text("Título") .font(.system(size: 28)) // ✅ Se adapta a las preferencias Text("Título") .font(.title) ``` ## Tu proyecto de práctica: Lista de tareas minimalista Vamos a juntar todo lo aprendido: ```swift struct ListaTareas: View { @State private var tareas = [ ("Comprar café ☕️", false), ("Aprender SwiftUI 📱", true), ("Conquistar el mundo 🌍", false) ] var body: some View { VStack(alignment: .leading, spacing: 20) { Text("Mis Tareas") .font(.largeTitle) .bold() Text("\(tareas.filter { $0.1 }.count) de \(tareas.count) completadas") .font(.subheadline) .foregroundColor(.secondary) VStack(spacing: 12) { ForEach(tareas.indices, id: \.self) { index in HStack { Text(tareas[index].0) .strikethrough(tareas[index].1) .foregroundColor(tareas[index].1 ? .secondary : .primary) Spacer() Button(action: { tareas[index].1.toggle() }) { Image(systemName: tareas[index].1 ? "checkmark.circle.fill" : "circle") .foregroundColor(tareas[index].1 ? .green : .gray) .font(.title2) } } .padding() .background(Color.gray.opacity(0.1)) .cornerRadius(10) } } } .padding() } } ``` ![La app de tareas funcionando con algunas tareas marcadas](https://firebasestorage.googleapis.com/v0/b/swiftly-by-warwere.firebasestorage.app/o/posts%2F04fe48fb-5412-4f1d-bb50-5b9d8b4e8360%2F1752433418959-8.webp?alt=media&token=6e03b8d3-192c-4d7e-aa2c-21ee9a8afea5) ## ¿Qué sigue? ¡Felicidades! 🎉 Ya dominas lo básico de Text en SwiftUI. Pero esto es solo el principio... En el próximo artículo aprenderás: - 📅 Cómo formatear fechas que se actualizan solas - 🌍 Hacer tu app multiidioma sin morir en el intento - ♿️ Accesibilidad que tus usuarios agradecerán - 🔗 Combinar textos como un pro ### Antes de irte... Practica con este reto: Crea una tarjeta de perfil de usuario que muestre: - Nombre en título grande - Email en texto secundario - Un contador de "Me gusta" que se pueda incrementar - Un estado (Activo/Inactivo) con colores ¿Lo tienes? ¡Compártelo en Twitter etiquetando a @aprendeswift! --- *¿Te gustó este artículo? ¡Hay mucho más de donde vino! Síguenos para no perderte el próximo donde haremos magia con fechas y números.* **El equipo de AprendeSwift.dev** (que sigo siendo yo solo, pero suena más pro así 😄)