Cách hiển thị dữ liệu phân cấp với SwiftUI 4

Nov 29 2022
Ai trong số các bạn chưa từng đối mặt với vấn đề hiển thị cấu trúc phân cấp trong một ứng dụng? SwiftUI cung cấp khả năng này chỉ với một vài dòng mã, sử dụng chế độ xem Danh sách và Nhóm phác thảo. Trong bài viết này, tôi sẽ chỉ cho bạn cách thực hiện việc này trong một vài bước.
Hình ảnh được cung cấp bởi Gerd Altmann , Pixabay

Ai trong số các bạn chưa từng đối mặt với vấn đề hiển thị cấu trúc phân cấp trong một ứng dụng?

SwiftUI cung cấp khả năng này chỉ với một vài dòng mã, sử dụng chế độ xem Danh sáchNhóm phác thảo . Trong bài viết này, tôi sẽ chỉ cho bạn cách thực hiện việc này trong một vài bước.

Giả sử chúng ta cần hiển thị thông tin phân cấp trong chế độ xem Danh sách, cho phép người dùng ẩn và hiển thị các phần khác nhau của phân cấp.

Chẳng hạn, chúng tôi muốn điều hướng phần sau của hệ thống tệp, bao gồm các thư mục và tệp. Đây là một cây phân cấp điển hình.

Sau đó bắt đầu và khởi chạy Xcode để tạo dự án Ứng dụng mới có tên HierarchicalDemo:

Bước đầu tiên là tạo ra một cấu trúc mô hình hóa một nút của cây phân cấp. Trong trình kiểm tra dự án, trong nhóm Mô hình , chúng tôi tạo một tệp nhanh có tên NodeInfo.swift và xác định cấu trúc NodeInfo :

Mỗi nút có một tên, một hình ảnh và một màu sắc đại diện cho nó tùy thuộc vào việc nó là một thư mục hay một tập tin, nó có thể có các nút con. Cấu trúc tuân theo giao thức Có thể nhận dạng , để mỗi phiên bản có thể được xác định duy nhất trong dạng xem Danh sách.

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)
        }
    }
}

Bây giờ chúng ta có một mô hình cho một nút của cấu trúc phân cấp và một dạng xem cho một hàng trong dạng xem Danh sách. Bước tiếp theo là xác định trong cấu trúc ContentView mảng không đổi NodeItems triển khai cây hệ thống tệp ở trên:

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)])]

Vì chúng tôi muốn danh sách có tiêu đề tùy chỉnh, trong ContentView.swift , chúng tôi xác định cấu trúc 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)
    }
}

Bây giờ là lúc để xây dựng danh sách phân cấp của chúng tôi. Trong nội dung contentView, chúng tôi nhập mã bên dưới:

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())
    }

Và đây là kết quả cuối cùng: