【问题标题】:SwiftUI how to refactor list item into a subviewSwiftUI如何将列表项重构为子视图
【发布时间】:2019-11-01 23:20:41
【问题描述】:

我一直在尝试为一个简单的 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
    }
}

【问题讨论】:

    标签: swiftui swiftui-list


    【解决方案1】:

    如果您使用@state,我发现您所做的一切至少在这些视图部分都是正确的。

           / 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。部分。

    【讨论】:

    • 理想情况下,我只想传递该项目。我确实找到了一种 hack 方式来传递模型并让它刷新 - 生病了
    • 你需要@publisher / 和可观察对象。
    • 我有这些 - 我想只是设置不理想
    【解决方案2】:

    这行得通 - 想知道我认为它是一种体面的方法

    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)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-10-13
      • 2020-08-22
      • 2019-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多