我一直在尝试为一个简单的SwiftUI项目创建较小的可重用视图。但是,我得到了意想不到的结果,并且努力理解原因。
这是我精心设计的突出问题的示例
使用此示例,您应该如何创建可重复使用的 RowView 来代替列表中的HStack
var body: some View {
List(vm.gradings) { item in
// how should you refactor out this ??
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
我正在使用Firebase触发模型更改。也就是说,将分数更改为通过或不及格,并期望列表详细信息视图显示该更改。
以上方法按预期工作,但在列表视图上,并且当数据更改时行也会更改。
但是,当我尝试重构该视图时,只有一个可以正常工作。理想情况下,我想传递Grading
对象,但这不会导致视图刷新。
尝试不同的子视图及其结果
var body: some View {
List(vm.gradings) { item in
// Works
RowA(grade: item.grade, pass: item.pass)
// Fails
// RowB(item: item)
// Fails
// RowC(item: item)
// Default - works as expected
// HStack {
// Text(item.grade)
// Text(item.pass ? "Pass" : "Fail")
// }
}
}
这是3行选项
// Works
struct RowA: View {
var grade: String
var pass: Bool
var body: some View {
HStack {
Text(grade)
Text(pass ? "Pass" : "Fail")
}
}
}
// Fails
struct RowB: View {
var item: Grading
var body: some View {
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
// Fails
struct RowC: View {
@State var item: Grading
var body: some View {
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
解决方法
// Allows me to pass in just the model
struct RowD: View {
private var item = Grading()
private var grade: String = ""
private var pass: Bool = false
init(item: Grading) {
self.item = item
self.grade = item.grade
self.pass = item.pass
}
var body: some View {
HStack {
Text(grade)
Text(pass ? "Pass" : "Fail")
}
}
}
我的视图模型
class StudentGradingsUIViewModel: ObservableObject {
@Published var detailedstudent: DetailedStudent
var gradings: [Grading] {
detailedstudent.student.gradings
}
init(student: DetailedStudent) {
self.detailedstudent = student
}
}
答案 0 :(得分:0)
如果您使用@state,我发现您所做的一切至少在这些View部分中是正确的。
/ Works
struct RowA: View {
var grade: String
var pass: Bool
var body: some View {
HStack {
Text(grade)
Text(pass ? "Pass" : "Fail")
}
}
}
//// Fails
struct RowB: View {
var item: Grading
var body: some View {
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
//
//// Fails
struct RowC: View {
@State var item: Grading
var body: some View {
HStack {
Text(item.grade)
Text(item.pass ? "Pass" : "Fail")
}
}
}
struct Grading: Identifiable{
var id = UUID()
var grade : String
var pass : Bool
}
struct TempGradingView: View {
@State var gradings: [Grading] = [Grading.init(grade: "50", pass: false),Grading.init(grade: "100", pass: true),Grading.init(grade: "100", pass: true)]
var body: some View {
Group{
Button("change", action: {
self.gradings[0].grade = "70"
})
List(gradings) { item in
// Works
// RowA(grade: item.grade, pass: item.pass)
// Fails
RowB(item: item)
// Fails
// RowC(item: item)
// Default - works as expected
// HStack {
// Text(item.grade)
// Text(item.pass ? "Pass" : "Fail")
// }
}}
}
}
因此,我认为存在问题的部分,即@publisher var。部分。
答案 1 :(得分:0)
这有效-想知道我认为这是一种体面的方法
private func gradingRow(_ grading: Grading) -> some View {
HStack {
Text(grading.grade)
.foregroundColor(grading.pass ? Color(UIColor.systemGreen) : Color(UIColor.systemRed))
Spacer()
Text(DateString.dateAsDDMMYYTime(from: grading.date))
.font(.subheadline)
}
}