วิธีแสดงข้อมูลลำดับชั้นด้วย SwiftUI 4

Nov 29 2022
มีใครบ้างที่ไม่เคยประสบปัญหาในการแสดงโครงสร้างลำดับชั้นภายในแอป SwiftUI นำเสนอความเป็นไปได้นี้ด้วยโค้ดเพียงไม่กี่บรรทัด โดยใช้มุมมองรายการและ OutlineGroup ในบทความนี้ฉันจะแสดงวิธีทำในไม่กี่ขั้นตอน
ภาพโดย Gerd Altmann จาก Pixabay

มีใครบ้างที่ไม่เคยประสบปัญหาในการแสดงโครงสร้างลำดับชั้นภายในแอป

SwiftUI นำเสนอความเป็นไปได้นี้ด้วยโค้ดเพียงไม่กี่บรรทัด โดยใช้มุมมองรายการและOutlineGroup ในบทความนี้ฉันจะแสดงวิธีทำในไม่กี่ขั้นตอน

สมมติว่าเราต้องแสดงข้อมูลลำดับชั้นภายในมุมมองรายการ ทำให้ผู้ใช้สามารถซ่อนและแสดงส่วนต่างๆ ของลำดับชั้นได้

ตัวอย่างเช่น เราต้องการนำทางส่วนต่อไปนี้ของระบบไฟล์ ซึ่งรวมถึงไดเร็กทอรีและไฟล์ นี่คือต้นไม้ลำดับชั้นทั่วไป

จากนั้นเริ่มต้นและเปิดใช้งาน Xcode เพื่อสร้างโครงการแอปใหม่ที่ชื่อว่า HierarchicalDemo:

ขั้นตอนแรกคือการสร้างโครงสร้างที่จำลองโหนดของแผนผังลำดับชั้น ในตัวตรวจสอบโครงการ ภายใต้ กลุ่ม Modelเราสร้างไฟล์ swift ชื่อNodeInfo.swiftและกำหนดโครงสร้างNodeInfo :

แต่ละโหนดมีชื่อ รูปภาพ และสีที่แสดงถึงโหนดนั้น ขึ้นอยู่กับว่าเป็นไดเร็กทอรีหรือไฟล์ โหนดสามารถมีโหนดย่อยได้ โครงสร้างเป็นไปตามIdentifiable protocol เพื่อให้แต่ละอินสแตนซ์สามารถระบุได้โดยไม่ซ้ำกันภายในมุมมองรายการ

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

ตอนนี้เรามีโมเดลสำหรับโหนดของลำดับชั้นและมุมมองสำหรับแถวในมุมมองรายการ ขั้นตอนต่อไปคือการกำหนดในโครงสร้าง ContentView ของอาร์เรย์คงที่NodeItemsที่นำแผนผังระบบไฟล์ไปใช้ ด้านบน:

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

เนื่องจากเราต้องการให้รายการมีส่วนหัวที่กำหนดเอง ในContentView.swiftเราจึงกำหนดโครงสร้าง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)
    }
}

ตอนนี้ได้เวลาสร้างรายการลำดับชั้นของเราแล้ว ในเนื้อหา contentView เราพิมพ์รหัสด้านล่าง:

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

และนี่คือผลลัพธ์สุดท้าย: