SwiftUI如何将列表项重构为子视图
Posted
技术标签:
【中文标题】SwiftUI如何将列表项重构为子视图【英文标题】:SwiftUI how to refactor list item into a subview 【发布时间】: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
【问题讨论】:
【参考方案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)
【讨论】:
以上是关于SwiftUI如何将列表项重构为子视图的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI - 如何基于@ObservedObject 为每个列表视图项创建编辑视图