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 应该显示 activityImage1
和 activity1
以及 activityImage2
和 activity2
。另一个 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 {
...
}
}
我正在使用 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 应该显示 activityImage1
和 activity1
以及 activityImage2
和 activity2
。另一个 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 {
...
}
}