NavigationSplitView también permite construir el patrón de navegación "master"/"content"/"detail", que básicamente son tres columnas, donde "master" suele ocultarse mientras se presenta "content" y "detail".
Estructura de datos
Vamos a usar la misma estructura de datos del ejemplo de "master"/"detail".
struct Item: Identifiable, Hashable {
let id: UUID = UUID()
let title: String
let children: [Item]?
}
Y el mismo dataset:
let items: [Item] = [
.init(title: "Súpergrupo 1", children: [
.init(title: "Grupo 1", children: [
.init(title: "Hoja 1", children: nil),
.init(title: "Hoja 2", children: nil),
.init(title: "Hoja 3", children: nil),
])
]),
.init(title: "Súpergrupo 2", children: [
.init(title: "Grupo 2", children: [
.init(title: "Hoja 4", children: nil),
.init(title: "Hoja 5", children: nil),
.init(title: "Hoja 6", children: nil),
]),
.init(title: "Grupo 3", children: [
.init(title: "Hoja 6", children: nil),
]),
]),
.init(title: "Súpergrupo 3", children: [
.init(title: "Grupo 4", children: [
.init(title: "Hoja 7", children: nil),
]),
.init(title: "Grupo 5", children: [
.init(title: "Hoja 7", children: nil),
.init(title: "Hoja 8", children: nil),
])
]),
]
Sidebar
En el bloque sidebar del NavigationSplitView sigue siendo un List que guarda el id del Item seleccionado.
@State private var selectedSupergroupId: Item.ID?
// ...
List(items, selection: $selectedSupergroupId) { supergroup in
Text(supergroup.title)
}
.listStyle(.sidebar)
.navigationTitle("Supergroups")
Content
El bloque content del NavigationSplitView se calcula de forma condicionada: Si el selectedSupergroupId es nil se pinta el Placeholder, sino se pinta un List que pinta a los hijos (children) del Item seleccionado.
Cuando se seleccione un Item en esta lista, se guardará su id en selectedGroupId.
@State private var selectedSupergroupId: Item.ID?
@State private var selectedGroupId: Item.ID?
if let selectedSupergroupId, let selectedSupergroup = items.first(where: { $0.id == selectedSupergroupId }), let groups = selectedSupergroup.children {
List(groups, selection: $selectedGroupId) { group in
Text(group.title)
}
.listStyle(.sidebar)
.navigationTitle("Groups")
} else {
Placeholder()
}
Detail
El bloque detail del NavigationSplitView también se calcula de forma condicionada: Se necesita que tanto selectedSupergroupId como selectedGroupId sean distintos de nil. En caso contrario, se pinta un Placeholder.
if let selectedSupergroupId, let selectedGroupId, let selectedSupergroup = items.first(where: { $0.id == selectedSupergroupId }), let groups = selectedSupergroup.children, let selectedGroup = groups.first(where: { $0.id == selectedGroupId }), let firstItem = selectedGroup.children?.first {
DetailView(item: firstItem)
} else {
Placeholder()
}
Código final
A continuación se presenta el código completo y algunas capturas de pantalla:
struct ContentView: View {
@State private var selectedSupergroupId: Item.ID?
@State private var selectedGroupId: Item.ID?
@State private var visibility: NavigationSplitViewVisibility = .automatic
var body: some View {
NavigationSplitView(columnVisibility: $visibility) {
List(items, selection: $selectedSupergroupId) { supergroup in
Text(supergroup.title)
}
.listStyle(.sidebar)
.navigationTitle("Supergroups")
} content: {
if let selectedSupergroupId, let selectedSupergroup = items.first(where: { $0.id == selectedSupergroupId }), let groups = selectedSupergroup.children {
List(groups, selection: $selectedGroupId) { group in
Text(group.title)
}
.listStyle(.sidebar)
.navigationTitle("Groups")
} else {
Placeholder()
}
} detail: {
if let selectedSupergroupId, let selectedGroupId, let selectedSupergroup = items.first(where: { $0.id == selectedSupergroupId }), let groups = selectedSupergroup.children, let selectedGroup = groups.first(where: { $0.id == selectedGroupId }), let firstItem = selectedGroup.children?.first {
DetailView(item: firstItem)
} else {
Placeholder()
}
}
}
}


Top comments (0)