SwiftUI:分层的可选列表
SwiftUI: Hierarichal, Selectable List
过去几天我一直在研究一个问题,但我似乎不知道如何解决它。
我想实现一个 分层系统 的 material 组,其中叶子将是特定的 material。
我基本上有 两个 CoreData 实体 、Material
和 MaterialGroup
。
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()
}
}
过去几天我一直在研究一个问题,但我似乎不知道如何解决它。
我想实现一个 分层系统 的 material 组,其中叶子将是特定的 material。
我基本上有 两个 CoreData 实体 、Material
和 MaterialGroup
。
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()
}
}