如何使代码更简单,更易于在 swiftui 中使用多维字典导航链接重用?
how to make the code simpler and more reusable for navigation links with multi dimension dictionary in swiftui?
我有一个多级词典,我需要用它来建立导航链接。
现在我有一个 2 级深度字典:
let multiDimDict: [String: [[String: [String]]]]
= ["A": [["A1": ["A11", "A12"]], ["A2": ["A21", "A22"]]],
"B": [["B1": ["B11", "B12"]], ["B2": ["B21", "B22"]]]
]
我可以构建包含所有导航链接的导航视图。但是,我觉得我在构建导航链接时以某种方式重复了一些代码。问题是,如果我有一个多级字典,比如说 10 级,我认为构建 10 个不同的子视图生成器来构建完整的导航视图是不明智的。知道如何减少代码吗?
struct PlayingWithMultiDimNavLink: View {
let multiDimDict: [String: [[String: [String]]]]
= ["A": [["A1": ["A11", "A12"]], ["A2": ["A21", "A22"]]],
"B": [["B1": ["B11", "B12"]], ["B2": ["B21", "B22"]]]
]
var body: some View {
NavigationView{
List {
ForEach(multiDimDict.keys.sorted(), id: \.self) { key in
NavigationLink(destination: GenerateChildView(key: key, dict: self.multiDimDict)){
Text(key)
}
}
}
}
}
}
这是:第一个子视图生成器:
struct GenerateChildView: View {
var key: String
var dict: [String: [[String: [String]]]]
var infoList: [[String: [String]]]
init(key: String, dict: [String: [[String: [String]]]] ){
self.key = key
self.dict = dict
self.infoList = dict[key]!
}
var body: some View {
List{
ForEach(infoList, id: \.self){ info in
self.getSomeView(infoList: self.infoList)
}
}
}
func getSomeView(infoList: [[String: [String]]] )-> AnyView{
let dictToUse = infoList[0]
return AnyView(
ForEach(dictToUse.keys.sorted(), id: \.self){ key2 in
NavigationLink(destination: GenerateChildView2(infoList: dictToUse[key2]!)){
Text(key2)
}
}
)
}
最后一个子视图生成器:
struct GenerateChildView2: View {
var infoList: [String]
init(infoList: [String]){
self.infoList = infoList
}
var body: some View {
List{
ForEach(infoList, id:\.self){ content in
Text(content)
}
}
}
}
我将从放弃使用字典开始,使用提供更有用模型的简单递归结构:
struct Item: Identifiable {
let id = UUID()
var title: String
var children: [Item] = []
}
然后你可以定义一个递归View
来显示这个模型:
struct NavView: View {
var item: Item
var body: some View {
NavigationView {
List {
ForEach(item.children) { child in
if child.children.isEmpty {
Text(child.title)
} else {
NavigationLink(destination: NavView(item:child)) {
Text(child.title)
}
}
}
}.navigationBarTitle(item.title)
}
}
}
然后您可以根据需要创建层次结构并将根传递给您的视图:
let root = Item(title:"",children:
[Item(title:"A",children:
[Item(title:"A1", children:
[Item(title:"A11"),Item(title:"A12")]
)]),
Item(title:"B",children:
[Item(title:"B1"),Item(title:"B2")]
)]
)
NavView(item:root))
从提供的快照中不清楚应该如何呈现字典列表,实际上,为什么它使用字典作为基本模型,但与不确定性无关,这里是可能的方向(不是最终的,但经过测试 &可以考虑)
struct PlayingWithMultiDimNavLink2: View {
let multiDimDict: [String: [[String: [String]]]]
= ["A": [["A1": ["A11", "A12"]], ["A2": ["A21", "A22"]]],
"B": [["B1": ["B11", "B12"]], ["B2": ["B21", "B22"]]]
]
var body: some View {
NavigationView{
GenericChildView(model: multiDimDict)
}
}
}
struct GenericChildView: View {
let model: [String: Any]
var body: some View {
List{
ForEach(model.keys.sorted(), id: \.self) { key in
self.nextLevelView(for: key)
}
}
}
private func nextLevelView(for key: String) -> some View {
let next = model[key]
return Group {
if next as? String != nil {
Text(next as! String)
} else if next as? [Any] != nil {
NavigationLink(destination: GenerateChildListView(infoList: next as! [Any]))
{ Text(key) }
} else if next as? [String: Any] != nil {
NavigationLink(destination: GenericChildView(model: next as! [String: Any]))
{ Text(key) }
}
}
}
}
struct GenerateChildListView: View {
var infoList: [Any]
init(infoList: [Any]){
self.infoList = infoList
}
var body: some View {
Group {
if infoList.count == 1 {
self.singleContentView()
}
if infoList.count > 1 {
List{
self.contentView()
}
}
}
}
private func singleContentView() -> some View {
return Group {
if infoList as? [String] != nil {
Text(infoList[0] as! String)
} else if infoList as? [[String: Any]] != nil {
GenericChildView(model: self.infoList[0] as! [String: Any])
}
}
}
private func contentView() -> some View {
return Group {
if infoList as? [String] != nil {
ForEach(infoList as! [String], id:\.self) { content in
Text(content)
}
} else if infoList as? [[String: Any]] != nil {
ForEach((infoList as! [[String: Any]]).indices, id: \.self) { i in
GenericChildView(model: self.infoList[i] as! [String: Any])
}
}
}
}
}
我有一个多级词典,我需要用它来建立导航链接。 现在我有一个 2 级深度字典:
let multiDimDict: [String: [[String: [String]]]]
= ["A": [["A1": ["A11", "A12"]], ["A2": ["A21", "A22"]]],
"B": [["B1": ["B11", "B12"]], ["B2": ["B21", "B22"]]]
]
我可以构建包含所有导航链接的导航视图。但是,我觉得我在构建导航链接时以某种方式重复了一些代码。问题是,如果我有一个多级字典,比如说 10 级,我认为构建 10 个不同的子视图生成器来构建完整的导航视图是不明智的。知道如何减少代码吗?
struct PlayingWithMultiDimNavLink: View {
let multiDimDict: [String: [[String: [String]]]]
= ["A": [["A1": ["A11", "A12"]], ["A2": ["A21", "A22"]]],
"B": [["B1": ["B11", "B12"]], ["B2": ["B21", "B22"]]]
]
var body: some View {
NavigationView{
List {
ForEach(multiDimDict.keys.sorted(), id: \.self) { key in
NavigationLink(destination: GenerateChildView(key: key, dict: self.multiDimDict)){
Text(key)
}
}
}
}
}
}
这是:第一个子视图生成器:
struct GenerateChildView: View {
var key: String
var dict: [String: [[String: [String]]]]
var infoList: [[String: [String]]]
init(key: String, dict: [String: [[String: [String]]]] ){
self.key = key
self.dict = dict
self.infoList = dict[key]!
}
var body: some View {
List{
ForEach(infoList, id: \.self){ info in
self.getSomeView(infoList: self.infoList)
}
}
}
func getSomeView(infoList: [[String: [String]]] )-> AnyView{
let dictToUse = infoList[0]
return AnyView(
ForEach(dictToUse.keys.sorted(), id: \.self){ key2 in
NavigationLink(destination: GenerateChildView2(infoList: dictToUse[key2]!)){
Text(key2)
}
}
)
}
最后一个子视图生成器:
struct GenerateChildView2: View {
var infoList: [String]
init(infoList: [String]){
self.infoList = infoList
}
var body: some View {
List{
ForEach(infoList, id:\.self){ content in
Text(content)
}
}
}
}
我将从放弃使用字典开始,使用提供更有用模型的简单递归结构:
struct Item: Identifiable {
let id = UUID()
var title: String
var children: [Item] = []
}
然后你可以定义一个递归View
来显示这个模型:
struct NavView: View {
var item: Item
var body: some View {
NavigationView {
List {
ForEach(item.children) { child in
if child.children.isEmpty {
Text(child.title)
} else {
NavigationLink(destination: NavView(item:child)) {
Text(child.title)
}
}
}
}.navigationBarTitle(item.title)
}
}
}
然后您可以根据需要创建层次结构并将根传递给您的视图:
let root = Item(title:"",children:
[Item(title:"A",children:
[Item(title:"A1", children:
[Item(title:"A11"),Item(title:"A12")]
)]),
Item(title:"B",children:
[Item(title:"B1"),Item(title:"B2")]
)]
)
NavView(item:root))
从提供的快照中不清楚应该如何呈现字典列表,实际上,为什么它使用字典作为基本模型,但与不确定性无关,这里是可能的方向(不是最终的,但经过测试 &可以考虑)
struct PlayingWithMultiDimNavLink2: View {
let multiDimDict: [String: [[String: [String]]]]
= ["A": [["A1": ["A11", "A12"]], ["A2": ["A21", "A22"]]],
"B": [["B1": ["B11", "B12"]], ["B2": ["B21", "B22"]]]
]
var body: some View {
NavigationView{
GenericChildView(model: multiDimDict)
}
}
}
struct GenericChildView: View {
let model: [String: Any]
var body: some View {
List{
ForEach(model.keys.sorted(), id: \.self) { key in
self.nextLevelView(for: key)
}
}
}
private func nextLevelView(for key: String) -> some View {
let next = model[key]
return Group {
if next as? String != nil {
Text(next as! String)
} else if next as? [Any] != nil {
NavigationLink(destination: GenerateChildListView(infoList: next as! [Any]))
{ Text(key) }
} else if next as? [String: Any] != nil {
NavigationLink(destination: GenericChildView(model: next as! [String: Any]))
{ Text(key) }
}
}
}
}
struct GenerateChildListView: View {
var infoList: [Any]
init(infoList: [Any]){
self.infoList = infoList
}
var body: some View {
Group {
if infoList.count == 1 {
self.singleContentView()
}
if infoList.count > 1 {
List{
self.contentView()
}
}
}
}
private func singleContentView() -> some View {
return Group {
if infoList as? [String] != nil {
Text(infoList[0] as! String)
} else if infoList as? [[String: Any]] != nil {
GenericChildView(model: self.infoList[0] as! [String: Any])
}
}
}
private func contentView() -> some View {
return Group {
if infoList as? [String] != nil {
ForEach(infoList as! [String], id:\.self) { content in
Text(content)
}
} else if infoList as? [[String: Any]] != nil {
ForEach((infoList as! [[String: Any]]).indices, id: \.self) { i in
GenericChildView(model: self.infoList[i] as! [String: Any])
}
}
}
}
}