SwiftUI:分层的可选列表

SwiftUI: Hierarichal, Selectable List

过去几天我一直在研究一个问题,但我似乎不知道如何解决它。

我想实现一个 分层系统 的 material 组,其中叶子将是特定的 material。
我基本上有 两个 CoreData 实体 MaterialMaterialGroup

MaterialGroup 有 3 个关系:subGroup(属于特定 MaterialGroup 的 MaterialGroup),superGroup(subGroup 的逆)和 subMaterial(层次结构的叶)。

我想要实现的理想场景是 selectable list of MaterialGroups,对于每个 selection I会有 3 个选项:
(1) - 在层次结构
的同一级别上创建 MaterialGroup (2) - 为 selection
创建 subGroup (3) - 为 MaterialGroup

创建一个 Material

当我可以创建这些层次结构但无法显示它们时,我只有一个没有深度的普通 selectable 列表。我无法弄清楚如何同时使列表可扩展和 select 可用。
就像 this。

我也想知道当我努力寻找一片叶子时如何 select 和 Material。如果我要使用 List(materialGroupArray, selection: $materialGroupSelection) 之类的东西,我就不能 select Material

如有任何提示,我将不胜感激。
祝你有个愉快的一天。

以下是分层列表的一种可能方法:

import SwiftUI

class Material {
    let name: String
    init(name: String) {
        self.name = name
    }
}

class MaterialGroup: Identifiable {
    let id: String
    var subGroup: MaterialGroup?
    let subMaterial: Material?

    init(id: String, subGroup: MaterialGroup?, subMaterial: Material?) {
        self.id = id
        self.subGroup = subGroup
        self.subMaterial = subMaterial
    }
}

let group1 = MaterialGroup(id: "G1",subGroup: nil, subMaterial: Material(name: "M1"))
let group2 = MaterialGroup(id: "G2",subGroup: nil, subMaterial: Material(name: "M2"))
let group3 = MaterialGroup(id: "G3",subGroup: group2, subMaterial: nil)
let group4 = MaterialGroup(id: "G4",subGroup: group3, subMaterial: nil)

let demoData: [MaterialGroup] = [
    group1,
    group4,
    MaterialGroup(id: "G5",subGroup: nil, subMaterial: Material(name: "M5"))

]

struct GroupView: View {
    let group: MaterialGroup
    @State var showChildRow = false
    @State var selected = false

    var hasChildren: Bool {
        group.subGroup != nil
    }

    var displayName: String {
        if let material = group.subMaterial {
            return material.name
        } else {
            return group.id
        }
    }

    var body: some View {
        HStack {
            if hasChildren {
                Image(systemName: showChildRow ? "chevron.down" : "chevron.right")
            }

            Text("\(displayName)").font(.caption2)
            Spacer()
        }.padding()
        .transition(.scale)
        .background(RoundedRectangle(cornerRadius: 15).fill(selected ? Color.red.opacity(0.1) : Color.black.opacity(0.1)))
        .onTapGesture {
            if hasChildren {
                withAnimation {
                    showChildRow.toggle()
                }
            } else {
                // You could use a closure here
                // onSelect: (Material) -> Void
                selected.toggle()
            }
        }

        if hasChildren && showChildRow {
            GroupView(group: group.subGroup!)
                .padding(.leading)
        }
    }
}


struct ContentView: View {
    var body: some View {
        ScrollView {
            ForEach(demoData) { group in
                VStack(alignment: .leading) {
                    GroupView(group: group)
                }
            }
        }.padding(.horizontal)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}