Si eres un iOS Developer que lleva años creando aplicaciones increíbles para el iPhone y el iPad, dar el salto al Mac puede parecer a la vez emocionante e intimidante. Las pantallas son más grandes, los usuarios interactúan con ratón y teclado, y la gestión de ventanas cambia por completo. Sin embargo, gracias a la programación Swift moderna, la barrera de entrada nunca ha sido tan baja.
Uno de los cambios de paradigma más importantes al adaptar o crear una app para Mac es la navegación. Atrás quedaron los días de forzar un NavigationView o un UITabBarController en una pantalla de 14 pulgadas. Hoy, el estándar de oro es el NavigationSplitView en macOS y en SwiftUI.
En este tutorial exhaustivo, vamos a explorar qué es, por qué deberías usarlo y cómo implementar un NavigationSplitView en macOS y en SwiftUI paso a paso utilizando Xcode, aprovechando todo el poder de Swift.
¿Qué es NavigationSplitView en macOS y en SwiftUI?
Introducido en macOS 13 (Ventura) y iOS 16, NavigationSplitView es el componente arquitectónico fundamental para construir interfaces de múltiples columnas. Viene a reemplazar de forma definitiva a las antiguas listas anidadas dentro de NavigationView.
Para un iOS Developer, la mejor forma de entenderlo es pensar en la aplicación nativa de Mail o Notas del iPad o el Mac. Tienes una barra lateral (Sidebar) a la izquierda, una lista de mensajes en el centro (Content) y el detalle del mensaje a la derecha (Detail). NavigationSplitView gestiona esta disposición, el colapso de las columnas y las animaciones de forma automática según el tamaño de la ventana.
Ventajas clave de usar NavigationSplitView
- Nativo por defecto: Proporciona exactamente el mismo aspecto, comportamiento y rendimiento que las aplicaciones nativas de Apple.
- Gestión automática del estado: SwiftUI maneja automáticamente qué columna debe mostrarse si el usuario reduce el tamaño de la ventana en macOS.
- Código unificado: El mismo código puede compilarse para el iPad (mostrando columnas) y para el iPhone (apilando las vistas en un estilo de navegación tradicional
NavigationStack).
Preparando tu entorno en Xcode
Antes de empezar a codificar, asegúrate de cumplir con los requisitos mínimos para aprovechar esta API al máximo:
- IDE: Xcode 14.0 o superior (recomendado Xcode 15+).
- Lenguaje: Swift 5.7+.
- Target: macOS 13.0 o superior.
Paso 1: La Arquitectura de 2 Columnas (Sidebar y Detail)
La implementación más sencilla de un NavigationSplitView en macOS y en SwiftUI consta de dos áreas: una barra lateral para la navegación principal y un área de detalle. Este patrón es ideal para paneles de configuración o aplicaciones de gestión sencillas.
Vamos a crear una aplicación que muestra una lista de lenguajes de programación y, al seleccionar uno, muestra su descripción.
import SwiftUI
// Nuestro modelo de datos básico
struct Lenguaje: Identifiable, Hashable {
let id = UUID()
let nombre: String
let descripcion: String
}
struct ContentView: View {
// Datos de ejemplo
let lenguajes: [Lenguaje] = [
Lenguaje(nombre: "Swift", descripcion: "El lenguaje potente e intuitivo de Apple."),
Lenguaje(nombre: "Objective-C", descripcion: "El predecesor de Swift, aún vivo en código legacy."),
Lenguaje(nombre: "Python", descripcion: "Excelente para scripting y machine learning.")
]
// El estado que guarda la selección actual
@State private var lenguajeSeleccionado: Lenguaje?
var body: some View {
// Inicializamos el NavigationSplitView de 2 columnas
NavigationSplitView {
// COLUMNA 1: BARRA LATERAL (Sidebar)
List(lenguajes, selection: $lenguajeSeleccionado) { lenguaje in
NavigationLink(value: lenguaje) {
Text(lenguaje.nombre)
}
}
.navigationTitle("Lenguajes")
} detail: {
// COLUMNA 2: DETALLE (Detail)
if let seleccionado = lenguajeSeleccionado {
VStack(spacing: 20) {
Text(seleccionado.nombre)
.font(.largeTitle)
.bold()
Text(seleccionado.descripcion)
.font(.title3)
.foregroundColor(.secondary)
}
.padding()
} else {
// Vista por defecto cuando no hay nada seleccionado
Text("Selecciona un lenguaje de la barra lateral")
.foregroundColor(.secondary)
}
}
}
}
Análisis del código para el iOS Developer
Nota cómo utilizamos un List con el parámetro selection: $lenguajeSeleccionado. En macOS, esto es crucial. A diferencia de iOS, donde tocas una celda y haces un “push” a otra pantalla, en macOS el usuario hace clic en un elemento de la lista y este queda resaltado (seleccionado), actualizando automáticamente la vista detail de la derecha.
Paso 2: La Arquitectura Avanzada de 3 Columnas
Las aplicaciones de escritorio más complejas, como Finder o Mail, utilizan tres columnas. El NavigationSplitView en macOS y en SwiftUI soporta esto de forma nativa añadiendo un bloque content intermedio.
Construyamos un ejemplo de un cliente de correo electrónico simulado:
import SwiftUI
struct Buzon: Identifiable, Hashable {
let id = UUID()
let nombre: String
let icono: String
let correos: [Correo]
}
struct Correo: Identifiable, Hashable {
let id = UUID()
let asunto: String
let remitente: String
let cuerpo: String
}
struct MailAppView: View {
// Estado para la columna 1 (Sidebar)
@State private var buzonSeleccionado: Buzon?
// Estado para la columna 2 (Content)
@State private var correoSeleccionado: Correo?
// Datos simulados
let buzones = [
Buzon(nombre: "Entrada", icono: "tray", correos: [
Correo(asunto: "Reunión de Xcode", remitente: "jefe@empresa.com", cuerpo: "Mañana a las 10 AM."),
Correo(asunto: "Novedades Swift", remitente: "apple@apple.com", cuerpo: "Descubre las nuevas APIs.")
]),
Buzon(nombre: "Borradores", icono: "doc", correos: [])
]
var body: some View {
NavigationSplitView {
// 1. BARRA LATERAL
List(buzones, selection: $buzonSeleccionado) { buzon in
NavigationLink(value: buzon) {
Label(buzon.nombre, systemImage: buzon.icono)
}
}
.navigationTitle("Buzones")
} content: {
// 2. CONTENIDO (Lista intermedia)
if let buzon = buzonSeleccionado {
List(buzon.correos, selection: $correoSeleccionado) { correo in
NavigationLink(value: correo) {
VStack(alignment: .leading) {
Text(correo.remitente).bold()
Text(correo.asunto).foregroundColor(.secondary)
}
}
}
.navigationTitle(buzon.nombre)
} else {
Text("Selecciona un buzón")
.foregroundColor(.secondary)
}
} detail: {
// 3. DETALLE
if let correo = correoSeleccionado {
ScrollView {
VStack(alignment: .leading, spacing: 10) {
Text(correo.asunto).font(.title).bold()
Text("De: \(correo.remitente)").foregroundColor(.secondary)
Divider()
Text(correo.cuerpo)
}
.padding()
}
.navigationTitle("Mensaje")
} else {
Text("Selecciona un correo para leerlo")
.foregroundColor(.secondary)
}
}
}
}
Personalización Específica para macOS
Como iOS Developer, estás acostumbrado a que el sistema decida mucho por ti. En macOS, los usuarios esperan tener control sobre sus ventanas. SwiftUI nos proporciona modificadores específicos para adaptar nuestra interfaz.
1. Controlar la Visibilidad de las Columnas
Puedes controlar programáticamente si la barra lateral está oculta o visible usando NavigationSplitViewVisibility.
@State private var visibilidad = NavigationSplitViewVisibility.all
var body: some View {
NavigationSplitView(columnVisibility: $visibilidad) {
// ... sidebar ...
} detail: {
// ... detail ...
}
}
2. Estilos de NavigationSplitView
Puedes cambiar cómo se comportan las columnas al redimensionar la ventana de la app en tu Mac. Añade el modificador .navigationSplitViewStyle() a tu vista principal.
.prominentDetail: Mantiene el área de detalle lo más grande posible, reduciendo el contenido o la barra lateral si la ventana se hace pequeña..balanced: Intenta mantener un ancho proporcional entre las columnas (el comportamiento por defecto).
3. Integración con el Toolbar del Mac
En macOS, la barra de herramientas (Toolbar) en la parte superior de la ventana es fundamental. Las acciones principales de tu aplicación deben residir ahí, no en botones flotantes o pestañas inferiores.
detail: {
if let seleccionado = elementoSeleccionado {
DetalleView(elemento: seleccionado)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(action: {
print("Compartir elemento")
}) {
Label("Compartir", systemImage: "square.and.arrow.up")
}
}
}
}
}
Errores Comunes y Consejos para la Programación Swift en Mac
Al hacer la transición y empezar a usar NavigationSplitView en macOS y en SwiftUI, es fácil caer en algunas trampas si vienes con una mentalidad estrictamente móvil:
- Olvidar el estado de selección vacío: En un iPhone, el usuario casi siempre ve una lista primero. En un Mac, la aplicación se abre mostrando todas las columnas a la vez. Siempre debes proporcionar una vista de diseño (placeholder) atractiva en tu bloque
detailpara cuandoselectionesnil. - Forzar el NavigationStack: No envuelvas un
NavigationSplitViewdentro de unNavigationStack. Son mutuamente excluyentes a nivel de raíz. Si necesitas hacer un “push” tradicional dentro del área de detalle, puedes colocar elNavigationStackdentro del bloquedetail. - Ignorar el teclado: Los usuarios de Mac usan flechas arriba/abajo. Si utilizas correctamente el binding de
selectionen unList, SwiftUI habilitará la navegación por teclado gratuitamente.
Conclusión
Dominar el NavigationSplitView en macOS y en SwiftUI es el rito de iniciación moderno para cualquier iOS Developer que desee expandir su horizonte al escritorio. La elegancia con la que la programación Swift maneja la complejidad del redimensionamiento de ventanas, los estados de selección y las barras de herramientas hace que el desarrollo para Mac en Xcode sea una experiencia increíblemente productiva.
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










