SwiftUI watchOS 如何在单个 View 中将数组内容显示为子视图?

SwiftUI watchOS How to display array content as subviews in a single View?

我正在使用 SwiftUI 开发 Apple Watch 应用程序。这个想法是在 ContentView Body View 中使用四个单独的 subviews 在单个 watch ContentView 中显示不同的 activity 内容。我不想使用列表来显示 activity 内容,而是使用 ContentView 中的多个自定义视图。

我希望每个单独的 subview 显示我模型中的独特内容。

我的模型名为 QuadActivity,包含以下内容:

struct QuadActivity: Identifiable {

  let id = UUID()
  var activityImage: Image
  var activityTitle: String
}

我目前已经为 QuadActivity 创建了一个扩展,如下所示,以保存一些硬编码的测试数据:

extension QuadActivity {
  
  static func all() -> [QuadActivity] {
    
     return [
        QuadActivity(activityImage: activityImage1, activityTitle: "activity1"),
        QuadActivity(activityImage: activityImage2, activityTitle: "activity2"),
        QuadActivity(activityImage: activityImage3, activityTitle: "activity3"),
        QuadActivity(activityImage: activityImage4, activityTitle: "activity4")]
  }
}

我的 ContentView.swift Body 视图由一个嵌入了 2 个 HStack 的 VStack 组成。每个 HStack 包含 2 个我的 subviews,带有杂项间隔符和填充修饰符。每个 子视图 应显示实例 属性:

中数组元素之一的内容
 var activityArrayEntry = QuadActivity.all()

因此 HStack 1 应该显示 activityImage1activity1 以及 activityImage2activity2。另一个 HStack 应该显示项目 3 和 4 的数组元素。

我不知道如何访问每个 activityArrayEntry 数组元素并在 子视图.

中显示每个元素

我在想我可以使用:

ForEach(activityArrayEntry) { activity in
  VStack and embedded HStack code here}

并通过上面的 ForEach 循环显示 subview 内容。

但是,由于我所有的 VStack 和 HStack 以及 subview 代码都在 ForEach 循环中,因此所有 [=59] 都会显示相同的数组元素 activity 内容=]subviews 因为循环包含单次循环的所有视图信息。我希望每个 subview 显示唯一数组元素的内容之一。

如果我在每个 HStack subview 显示部分的 ZStack 和 HStack 代码中移动 ForEach,它将遍历数组条目,但循环不会包含所有subviews 代码,我不会让所有 subviews 只显示来自 1 个数组元素的 activity 数组内容。

也许使用 ForEach 循环不是办法。是否有另一种方法从我的实例变量访问单个数组元素,以便每个唯一数组元素仅在 子视图 之一中使用?

同样,如何让整体 ContentView.swift 显示 ZStack 和 HStack 结构中的四个 subviews,以便每个 subview 仅显示数组元素之一的 activity 内容。

这是我的 ContentView 到目前为止。请注意我最终会回来查看的一些注释行,以便使用来自我模型的@Published Observable Object 的 Observed Object 模型方法。这最终将是(也许)方法而不是我现在使用的模型中的函数 all() 和硬编码数据来测试我的应用程序中的数据流......因此原始 question/issue.

备注

调用 QuadView() 只是调用提取的子视图,我在其中定义子视图的显示(简单图像和文本):

import SwiftUI

struct ContentView: View {
    
//    @ObservedObject var quadViewVM = QuadViewVM()
    var activityArrayEntry = QuadActivity.all()
    
    var body: some View {
        
        ZStack {
            
            HStack {
                
                Divider()
                    .frame(height: 175.0)
                
            }
            .edgesIgnoringSafeArea(.horizontal)
            
            ForEach(activityArrayEntry) { activity in

            VStack {
                
                
                HStack(alignment: .center) {
                    QuadView(activityTitle: "\(activity.activityTitle)", activityImage: activity.activityImage)
                    
                        //                        NavigationLink(destination: QuadDetail(content: , newActivity: false)) {
                        //
                        //                        }
                        .frame(width: 85.0, height: 100.0)
                        .buttonStyle(PlainButtonStyle())
                    
                    Spacer()
                    
                    QuadView(activityTitle: "\(activity.activityTitle)", activityImage: activity.activityImage)
                    
                        //                        NavigationLink(destination: QuadDetail()) {
                        //
                        //                        }
                        
                        .frame(width: 85.0, height: 100.0)
                        .buttonStyle(PlainButtonStyle())
                }
                .padding(.horizontal, 15.0)
                .padding(.bottom, -10.0)
                
                Divider()
                
                HStack(alignment: .center) {
                    QuadView(activityTitle: "\(activity.activityTitle)", activityImage: activity.activityImage)
                    
                        //                        NavigationLink(destination: QuadDetail()) {
                        //
                        //                        }
                        
                        .frame(width: 85.0, height: 100.0)
                        .buttonStyle(PlainButtonStyle())
                    
                    Spacer()
                    
                    QuadView(activityTitle: "\(activity.activityTitle)", activityImage: activity.activityImage)
                    
                        //                        NavigationLink(destination: QuadDetail()) {
                        //
                        //                        }
                        .frame(width: 85.0, height: 100.0)
                        .buttonStyle(PlainButtonStyle())
                }
                    
                .padding([.leading, .bottom, .trailing], 15.0)
                .padding(.top, -10.0)
                    
                    
                .padding(.top, 30.0)
                .edgesIgnoringSafeArea(.horizontal)
                
            }
        }
    }
}
}

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

您可以将数据存储在 ViewModel:

中,而不是静态 QuadActivity.all()
class QuadViewVM: ObservableObject {
    @Published var quadActivities: [QuadActivity] = [
        QuadActivity(activityImage: activityImage1, activityTitle: "activity1"),
        QuadActivity(activityImage: activityImage2, activityTitle: "activity2"),
        QuadActivity(activityImage: activityImage3, activityTitle: "activity3"),
        QuadActivity(activityImage: activityImage4, activityTitle: "activity4"),
    ]
}

在您的 ContentView 中,您可以使用两个 ForEach 循环创建网格(因为它是二维网格):

struct ContentView: View {
    @ObservedObject var quadViewVM = QuadViewVM()
    let columnCount = 2
    var rowCount: Int {
        quadViewVM.quadActivities.count / columnCount
    }

    var body: some View {
        ZStack {
            // Horizontal divider
            VStack {
                Divider()
            }
            .edgesIgnoringSafeArea(.horizontal)
            // Vertical divider
            HStack {
                Divider()
            }
            .edgesIgnoringSafeArea(.vertical)

            activityGrid
        }
    }

    var activityGrid: some View {
        VStack {
            ForEach(0 ..< self.rowCount) { row in
                HStack {
                    ForEach(0 ..< self.columnCount) { column in
                        self.quadView(row: row, column: column)
                    }
                }
            }
        }
    }

    func quadView(row: Int, column: Int) -> some View {
        let activity = quadViewVM.quadActivities[row * columnCount + column]
        return QuadView(activity: activity)
            .frame(width: 85.0, height: 100.0)
            .buttonStyle(PlainButtonStyle())
    }
}

QuadView 被提取到另一个函数,以使其更具可读性和更容易应用视图修饰符。

我还建议将整个 QuadActivity 变量传递给 QuadView(而不是它的单个组件)——特别是当您需要它们时:

struct QuadView: View {
    let activity: QuadActivity

    var body: some View {
        ...
    }
}