Si eres un iOS Developer o estás en camino de convertirte en uno, sabes que mostrar colecciones de datos es una de las tareas más comunes y fundamentales en la creación de aplicaciones. En los días de UIKit, dependíamos de UITableView y sus delegados para lograr esto, lo que a menudo resultaba en cientos de líneas de código repetitivo. Hoy, gracias a la programación Swift moderna, tenemos una herramienta mucho más elegante y declarativa.
En este artículo, vamos a explorar a fondo cómo añadir secciones a una List con SwiftUI. No solo nos quedaremos en lo básico; construiremos un tutorial completo que abarque la implementación de estas listas no solo para el iPhone, sino adaptándolas a todo el ecosistema de Apple usando Swift, Xcode y SwiftUI para iOS, macOS y watchOS.
1. Comprendiendo la anatomía de una List en SwiftUI
Antes de empezar a teclear, es vital entender qué es exactamente una List en SwiftUI. Una List es un contenedor que presenta filas de datos dispuestas en una sola columna. Es el equivalente directo de UITableView en iOS, NSTableView en macOS y WKInterfaceTable en watchOS.
La magia de SwiftUI radica en su capacidad multiplataforma. Escribes el código de tu lista una vez, y el framework se encarga de renderizar el componente nativo adecuado según el dispositivo donde se esté ejecutando.
Para organizar mejor la información cuando tenemos muchos datos, necesitamos agruparlos. Aquí es donde entran las Section. Una sección nos permite dividir nuestra lista en bloques lógicos, añadiendo encabezados (headers) y pies de página (footers) para dar contexto al usuario.
2. Configuración del Proyecto en Xcode
Para comenzar, necesitamos configurar nuestro entorno de desarrollo.
- Abre Xcode y selecciona “Create a new Xcode project”.
- En la plantilla, selecciona la pestaña Multiplatform y elige App. Esto nos permitirá compartir nuestro código de SwiftUI entre iOS, macOS y watchOS.
- Nombra tu proyecto, por ejemplo,
MultiplatformListApp. - Asegúrate de que la interfaz esté configurada en SwiftUI y el lenguaje en Swift.
- Haz clic en Next y guarda el proyecto.
Al abrirse el proyecto, verás tu archivo ContentView.swift. Aquí es donde ocurrirá la mayor parte de nuestra magia de programación Swift.
3. El Enfoque Estático: Lo Básico de Añadir Secciones
La forma más sencilla de añadir secciones a una List con SwiftUI es hacerlo de manera estática. Esto es útil cuando conoces de antemano los elementos exactos que vas a mostrar (por ejemplo, un menú de configuración de la app).
Vamos a crear una lista estática con dos secciones: “General” y “Avanzado”.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationStack {
List {
// Primera Sección
Section(header: Text("General"), footer: Text("Opciones básicas de la aplicación.")) {
Text("Perfil")
Text("Notificaciones")
Text("Apariencia")
}
// Segunda Sección
Section(header: Text("Avanzado")) {
Text("Privacidad y Seguridad")
Text("Almacenamiento")
Text("Acerca de")
}
}
.navigationTitle("Ajustes")
}
}
}
Análisis del Código Estático
List: Crea el contenedor principal que permite el desplazamiento (scroll) vertical.Section: Envuelve un grupo de vistas. Toma parámetros opcionales paraheader(encabezado) yfooter(pie de página).NavigationStack: Nos permite añadir un título a la vista superior (.navigationTitle), lo cual es una práctica estándar para cualquier iOS Developer al diseñar interfaces de navegación.
Si previsualizas esto en el Canvas de Xcode, verás una lista perfectamente formateada con separadores y encabezados en mayúsculas pequeñas, el estilo por defecto en iOS.
4. El Enfoque Dinámico: Trabajando con Modelos de Datos
En el mundo real del desarrollo de apps, rara vez codificamos los datos de forma estática. Normalmente, los obtenemos de una API, una base de datos local (como CoreData o SwiftData) o un archivo JSON. Por lo tanto, necesitamos que nuestras secciones se generen dinámicamente.
Para dominar la programación Swift orientada a vistas, primero debemos crear modelos de datos robustos que conformen el protocolo Identifiable.
Creando los Modelos de Datos
Vamos a crear un escenario donde mostramos un catálogo de cursos de programación, divididos por categorías (por ejemplo: Desarrollo Móvil, Desarrollo Web).
Crea un nuevo archivo en Xcode llamado CourseModel.swift y añade el siguiente código:
import Foundation
// Modelo para el elemento individual
struct Course: Identifiable {
let id = UUID()
let name: String
let duration: String
}
// Modelo para la Sección
struct CourseCategory: Identifiable {
let id = UUID()
let categoryName: String
let courses: [Course]
}
Es crucial que ambos modelos adopten Identifiable y tengan una propiedad id. Esto permite a SwiftUI rastrear de manera eficiente los cambios en la interfaz de usuario, saber qué elemento animar, insertar o eliminar, lo que optimiza enormemente el rendimiento.
Generando Datos de Muestra
Añadamos una extensión para generar datos de prueba fácilmente:
extension CourseCategory {
static let sampleData: [CourseCategory] = [
CourseCategory(categoryName: "Desarrollo Móvil", courses: [
Course(name: "Introducción a Swift", duration: "4 horas"),
Course(name: "Master en SwiftUI", duration: "10 horas"),
Course(name: "Arquitecturas en iOS", duration: "6 horas")
]),
CourseCategory(categoryName: "Desarrollo Web", courses: [
Course(name: "Fundamentos de HTML y CSS", duration: "5 horas"),
Course(name: "JavaScript Moderno", duration: "8 horas")
]),
CourseCategory(categoryName: "Backend", courses: [
Course(name: "Vapor con Swift", duration: "7 horas"),
Course(name: "Bases de Datos SQL", duration: "5 horas")
])
]
}
Implementando la Lista Dinámica
Ahora, volvamos a nuestro ContentView.swift y usemos estos datos para añadir secciones a una List con SwiftUI usando bucles ForEach.
import SwiftUI
struct ContentView: View {
// Importamos nuestros datos de prueba
let categories = CourseCategory.sampleData
var body: some View {
NavigationStack {
List {
// Iteramos sobre las categorías para crear las secciones
ForEach(categories) { category in
Section(header: Text(category.categoryName)
.font(.headline)
.foregroundColor(.accentColor)) {
// Iteramos sobre los cursos dentro de la categoría
ForEach(category.courses) { course in
CourseRow(course: course)
}
}
}
}
.navigationTitle("Catálogo de Cursos")
}
}
}
// Extraemos la celda a una vista separada para un código más limpio
struct CourseRow: View {
let course: Course
var body: some View {
HStack {
VStack(alignment: .leading, spacing: 4) {
Text(course.name)
.font(.body)
.bold()
Text(course.duration)
.font(.caption)
.foregroundColor(.secondary)
}
Spacer()
Image(systemName: "chevron.right")
.foregroundColor(.gray)
.imageScale(.small)
}
.padding(.vertical, 4)
}
}
¿Por qué este enfoque te hace un mejor iOS Developer?
Extraer CourseRow en su propia estructura (struct) es una de las mejores prácticas en la programación Swift. Mantiene el cuerpo (body) de tu vista principal limpio, legible y modular. Si necesitas cambiar el diseño de la celda en el futuro, solo tienes que modificar CourseRow sin tocar la lógica de la List.
5. Adaptando la List para macOS y watchOS
Como prometimos, este tutorial es multiplataforma. Aunque el código de SwiftUI anterior funcionará en iOS, macOS y watchOS sin cambios, un buen desarrollador sabe que la Experiencia de Usuario (UX) varía drásticamente entre un reloj inteligente, un teléfono y un ordenador de escritorio.
Personalizando el Estilo de la Lista (.listStyle)
SwiftUI nos proporciona el modificador .listStyle() para adaptar el aspecto de nuestra lista.
En iOS y iPadOS
Para aplicaciones iOS modernas (estilo Ajustes), el estilo InsetGroupedListStyle es el estándar de oro para listas con secciones.
List {
// ... secciones ...
}
.listStyle(InsetGroupedListStyle()) // Recomendado para iOS 14+
Esto crea bordes redondeados alrededor de cada sección, haciéndolas parecer “tarjetas” flotantes sobre el fondo.
En macOS
En el Mac, las listas a menudo se comportan como barras laterales (sidebars) para la navegación, o como tablas completas. Podemos usar directivas de compilación condicionales o simplemente confiar en los estilos específicos.
#if os(macOS)
List {
// ... secciones ...
}
.listStyle(SidebarListStyle()) // Ideal para navegación en Mac
#else
List {
// ... secciones ...
}
.listStyle(InsetGroupedListStyle())
#endif
En watchOS
El Apple Watch tiene un espacio de pantalla extremadamente limitado. Las secciones pesadas con encabezados enormes pueden arruinar la experiencia. En watchOS, el estilo predeterminado CarouselListStyle o el simple PlainListStyle suelen ser suficientes.
6. Personalización Avanzada de Encabezados (Headers)
A menudo, el texto simple de un header no es suficiente. Quizás quieras añadir iconos, botones o un diseño completamente personalizado a las cabeceras de tus secciones. SwiftUI te permite pasar cualquier vista al parámetro header de una Section.
Vamos a mejorar nuestro código anterior para incluir un icono en el encabezado de la sección:
Section(header:
HStack {
Image(systemName: "folder.fill")
.foregroundColor(.blue)
Text(category.categoryName)
.font(.title3)
.bold()
.foregroundColor(.primary)
}
.padding(.bottom, 5)
) {
// ... filas ...
}
// Importante para iOS: para que los headers personalizados no se conviertan a mayúsculas
.textCase(nil)
Truco Pro de programación Swift: En iOS, los encabezados de las listas agrupadas por defecto transforman todo el texto a MAYÚSCULAS. Si pasas un diseño personalizado y quieres conservar las minúsculas originales, debes aplicar el modificador .textCase(nil) a la vista principal del contenedor o a la Section.
7. Interactividad: Expandir y Colapsar Secciones (iOS 14+ / macOS 11+)
Una de las características más demandadas al añadir secciones a una List con SwiftUI es la capacidad de colapsar o expandir secciones. Desde iOS 14 y macOS 11, Apple introdujo DisclosureGroup y listas jerárquicas integradas.
Podemos modificar nuestra sección para permitir que el usuario la oculte si no le interesa:
// Necesitamos un estado para controlar qué categorías están expandidas
// (Para un ejemplo simple, usaremos DisclosureGroup que gestiona su propio estado temporal)
List {
ForEach(categories) { category in
Section {
DisclosureGroup(
content: {
ForEach(category.courses) { course in
CourseRow(course: course)
}
},
label: {
Text(category.categoryName)
.font(.headline)
.foregroundColor(.blue)
}
)
}
}
}
.listStyle(.insetGrouped)
Nota: Si bien DisclosureGroup es potente, a veces rompe la estética de la Section tradicional de iOS, por lo que debes evaluar si encaja con el diseño UI/UX de tu aplicación.
8. Optimizando el Rendimiento en Listas Grandes
Como iOS Developer, debes preocuparte por la memoria y el rendimiento, especialmente cuando tienes listas que podrían contener miles de registros.
La buena noticia es que List en SwiftUI es “perezosa” (lazy) por defecto. Esto significa que Xcode y el sistema operativo no instancian en memoria las vistas de las filas que no están actualmente visibles en la pantalla, de manera muy similar a como UITableView reciclaba sus celdas.
Sin embargo, hay trampas que debes evitar en la programación Swift:
- Evita cálculos pesados dentro del
bodyde tu Row: Si tuCourseRownecesita descargar una imagen o realizar un cálculo matemático complejo, asegúrate de hacerlo asíncronamente o procesarlo antes en el ViewModel (patrón MVVM). - Usa
idúnicos y estables: Asegúrate de que tuUUIDo el identificador que uses paraIdentifiableno cambie cada vez que la vista se repinte. Si cambias los IDs constantemente, SwiftUI destruirá y recreará la lista completa, lo que arruinará el rendimiento de tu app.
Conclusión
Dominar cómo añadir secciones a una List con SwiftUI es un requisito indispensable para cualquier iOS Developer. Hemos pasado de tener que implementar delegados, data sources y contar el número de secciones y filas manualmente con Swift y UIKit, a simplemente describir cómo queremos que se vea nuestra interfaz de manera declarativa usando Xcode y SwiftUI.
A lo largo de este tutorial, hemos cubierto:
- La estructura básica estática de las secciones.
- La generación dinámica utilizando modelos de datos conformes a
Identifiable. - La adaptación del diseño entre iOS, macOS y watchOS.
- La personalización de cabeceras.
- Consejos de rendimiento y mejores prácticas en la programación Swift.
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









