Cómo mostrar datos jerárquicos con SwiftUI 4

Nov 29 2022
¿Quién de ustedes nunca se ha enfrentado al problema de mostrar estructuras jerárquicas dentro de una aplicación? SwiftUI ofrece esta posibilidad con solo unas pocas líneas de código, utilizando las vistas Listas y Esquema de grupo. En este artículo te mostraré cómo hacer esto en unos pocos pasos.
Imagen de Gerd Altmann , Pixabay

¿Quién de ustedes nunca se ha enfrentado al problema de mostrar estructuras jerárquicas dentro de una aplicación?

SwiftUI ofrece esta posibilidad con solo unas pocas líneas de código, utilizando las vistas Listas y Esquema de grupo . En este artículo te mostraré cómo hacer esto en unos pocos pasos.

Supongamos que necesitamos mostrar información jerárquica dentro de una vista de lista, lo que permite al usuario ocultar y mostrar diferentes secciones de la jerarquía.

Por ejemplo, queremos navegar por la siguiente parte de un sistema de archivos, que incluye directorios y archivos. Este es un árbol jerárquico típico.

Luego inicie y ejecute Xcode para crear el nuevo proyecto de aplicación llamado HierarchicalDemo:

El primer paso es la creación de una estructura que modele un nodo de árbol jerárquico. En el inspector del proyecto, en el grupo Modelo , creamos un archivo Swift llamado NodeInfo.swift y definimos la estructura NodeInfo :

Cada nodo tiene un nombre, una imagen y un color que lo representan dependiendo si es un directorio o un archivo, puede tener nodos hijos. La estructura se ajusta al protocolo identificable , de modo que cada instancia se puede identificar de forma única dentro de la vista de lista.

struct NodeInfo: Identifiable{
    var id = UUID()
    var name: String
    var image: String
    var color: Color
    var children: [NodeInfo]?
 }

struct NodeCell: View {
    var nodeItem: NodeInfo
    var body: some View {
        HStack{
            Image(systemName: nodeItem.image)
                .resizable()
                .scaledToFit()
                .frame(width: 25,height: 25)
                .foregroundColor(nodeItem.color)
            Text(nodeItem.name)
        }
    }
}

Ahora tenemos un modelo para un nodo de la jerarquía y una vista para una fila en la vista Lista. El siguiente paso es definir en la estructura de ContentView la matriz constante NodeItems que implementa el árbol del sistema de archivos, arriba:

let nodeItems: [NodeInfo] =
    [NodeInfo(name: "ROOT", image: "folder",color: .orange, children:
            [NodeInfo(name:"Documents", image: "folder.circle",color: .blue, children:[NodeInfo(name: "Accounting", image: "folder.circle",color: .blue, children: [NodeInfo(name: "rental.doc", image: "doc.circle",color: .cyan),NodeInfo(name: "invoice1.doc", image: "doc.circle", color: .cyan),NodeInfo(name: "invoice2.doc", image: "doc.circle",color: .cyan)])]),
             NodeInfo(name: "Photo", image: "folder.circle",color: .blue, children: [NodeInfo(name: "Selfie", image: "folder.circle",color:.blue,children: [NodeInfo(name: "john.png", image: "photo.circle",color: .green),NodeInfo(name: "Julie.png", image: "photo.circle",color: .green)]),NodeInfo(name: "mybirthday.png", image: "photo.circle",color: .green)]),
             NodeInfo(name: "Video", image: "folder.circle",color:.blue, children: [NodeInfo(name: "Holiday", image: "folder.circle",color:.blue,children: [NodeInfo(name: "mountins.wav", image: "video.circle",color: .orange),NodeInfo(name: "sea.wav", image: "video.circle",color:.orange)]),NodeInfo(name: "birthday.mp3", image: "video.circle.fill",color:.orange),NodeInfo(name: "cat.wav", image: "video.circle",color:.orange)]),
             NodeInfo(name: "booking.pdf", image: "doc.circle",color: .green)])]

Como queremos que la lista tenga un encabezado personalizado, en ContentView.swift definimos una estructura SectionHeader :

struct SectionHeader: View{
    var nodeItem: NodeInfo
    var body: some View{
        HStack{
            Image(systemName: nodeItem.image)
                .resizable()
                .scaledToFit()
                .frame(width: 25, height: 25)
            Text(nodeItem.name)
                .font(.title2.bold())
        }
        .foregroundColor(nodeItem.color)
    }
}

Ahora es el momento de construir nuestra lista jerárquica. En contentView body escribimos el siguiente código:

var body: some View {
        List{
            ForEach(nodeItems) { item in
                
                Section(header: SectionHeader(nodeItem: item)){
                    
                    OutlineGroup(item.children ?? [NodeInfo](), children: \.children){child in
                        
                       NodeCell(nodeItem: child)
                        
                    }
                }
            }
        }
        .listStyle(InsetListStyle())
    }

Y este es el resultado final: