如何解决使用PreferenceKeys的递归树结构中的SwiftUI自定义对齐指南
我一直在尝试在SwiftUI中创建树形图视图,并且在此博客帖子here的帮助下,制作了一个简单而实用的树形图。但是,我需要实现一些特定的格式要求,其中之一是树上的节点必须以其直接子节点为中心。到目前为止,我已经实现了将每个节点的整个子树而不是其直接子节点作为整个中心的问题。
这是我现在实现的简化版本,它使用递归来绘制节点视图,并使用首选项来绘制节点之间的边缘:
import SwiftUI
struct Node: Hashable,Identifiable {
var id = UUID()
var text: String
var children: [Node]?
}
//data to collect from nodes in tree
struct NodePositionData {
var top: Anchor<CGPoint>? = nil
var bottom: Anchor<CGPoint>? = nil
}
//preference data stored in a dictionary
struct NodePositionsPreferenceKey: PreferenceKey {
typealias Value = [UUID:NodePositionData]
static var defaultValue: [UUID:NodePositionData] = [:]
static func reduce(value: inout [UUID : NodePositionData],nextValue: () -> [UUID : NodePositionData]) {
value.merge(nextValue(),uniquingKeysWith: { $1 })
}
}
struct NodeView: View {
var node: Node
var body: some View {
Text(node.text).font(.system(size: 16))
.anchorPreference(key: NodePositionsPreferenceKey.self,value: .top,transform: { anchor in
[self.node.id: NodePositionData(top: anchor)]
})
.transformAnchorPreference(key: NodePositionsPreferenceKey.self,value: .bottom,transform: { value,anchor in
value[self.node.id]!.bottom = anchor
})
}
}
struct TreeView: View {
var tree: Node
var body: some View {
VStack(alignment: .center) {
NodeView(node: tree)
.padding(.vertical,7)
.padding(.horizontal,3)
if(tree.children != nil){
HStack(alignment: .top,spacing: 10) {
ForEach(tree.children!) { child in
//recursive tree view for each child
TreeView(tree: child)
}
}
}
}//draw edges between nodes and their children
.backgroundPreferenceValue(NodePositionsPreferenceKey.self) { preference in
GeometryReader { geometry in
if(self.tree.children != nil){
ForEach(self.tree.children!,id: \.id,content: { child in
Line(
from: geometry[preference[self.tree.id]!.bottom!],to: geometry[preference[child.id]!.top!]
).stroke()
})
}
}
}
}
}
struct Line: Shape {
var from: CGPoint
var to: CGPoint
func path(in rect: CGRect) -> Path {
Path { p in
p.move(to: self.from)
p.addLine(to: self.to)
}
}
}
以下是一些数据的示例:
let sampleData =
Node(text: "level 0",children: [
Node(text: "level 1"),Node(text: "level 1",children:
[Node(text: "level 2"),Node(text: "level 2"),Node(text: "level 2",children:
[Node(text: "level 3"),Node(text: "level 3")
])
])
])
struct Model_Previews: PreviewProvider {
static var previews: some View {
TreeView(tree: sampleData)
}
}
如您所见,每个节点都不以其直接子节点居中。
我解决此问题的第一个想法是制作自定义对齐指南;即使在阅读完所有关于它们的知识并进行了一些实验之后,我还是真的不太理解对齐指南,而且绝对不够好,无法将其应用于该特定解决方案。
关于如何在此处使用对齐指南的任何建议,或者这种情况下的这种推理方式是否可行?
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。