【问题标题】:SwiftUI watchOS How to display array content as subviews in a single View?SwiftUI watchOS 如何在单个视图中将数组内容显示为子视图?
【发布时间】:2020-10-03 13:39:14
【问题描述】:

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

我希望每个单独的 子视图 显示来自我的模型的独特内容。

我的模型叫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 应该显示 activityImage1activity1activityImage2activity2。另一个 HStack 应该显示项目 3 和 4 的数组元素。

我不知道如何访问每个 activityArrayEntry 数组元素并在其中一个子视图中显示每个元素。

我在想我可以使用:

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

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

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

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

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

再次,如何让整体ContentView.swift显示ZStack和HStack结构内的四个subview,使得每个subview只显示1个activity内容数组元素。

到目前为止,这是我的ContentView。请注意一些注释行,为了从我的模型的 @Published Observable Object 使用 Observed Object 模型方法,我最终会回到这些行。这最终将(可能)成为方法,而不是我现在使用硬编码数据使用模型中的函数 all() 来测试我的应用程序中的数据流......因此是原始问题/问题。

注意

调用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()
    }
}

【问题讨论】:

    标签: arrays swiftui watchos


    【解决方案1】:

    您可以将数据存储在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 {
            ...
        }
    }
    

    【讨论】:

    • 非常感谢您的意见。我看到通过使用带有行和列参数的嵌套 ForEach 循环,您可以定位我想做的特定数组 Lee Lime。我会尝试这种方法并报告。
    • 我使用了这种方法,并且通过一点 .padding() 操作,这很有效。我还能够继续前进并添加一个 NavigationLink 以将我带到我的 DetailView。谢谢你。现在我希望 Apple 能在 WWDC20 上宣布一种更简单的方式来进行网格/集合视图。
    • @andyzoom01 仅供参考,在 SwiftUI 2 中,您可以使用原生 Grids,请参阅 SwiftUI Lazy Grid Tutorial
    猜你喜欢
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 2022-06-23
    • 1970-01-01
    • 2019-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多