ios - 模型更新前 SwiftUI 视图重新渲染
问题描述
为什么我的视图在更新完成之前呈现模型更新?或者至少看起来是这样。看起来,它是根据我模型的先前值重新绘制的。
我在做什么:当您点击一个人单元格时,它会将那个人标记为“已选中”,然后将前景色更改为绿色。如果未选择它们,则前景色为白色。
发生了什么:重要的是要注意这并不总是发生。似乎是随机的。但偶尔,当我点击一个人的单元格时,颜色不会改变。而且我已经深入挖掘,那是因为它(看起来)在我的PeopleStore
模型对象中的值发生变化之前重绘了视图。
这是代码:
struct PersonCell: View {
@EnvironmentObject var peopleStore: PeopleStore
var personId: UUID
var person: Person {
return peopleStore.people.filter({ $0.id == personId }).first!
}
var body: some View {
Button(action: {
print("Tapped Cell: " + peopleStore.personName(id: personId))
peopleStore.toggleSelectionOfPerson(with: personId)
}) {
GeometryReader { geo in
ZStack {
Rectangle().foregroundColor(peopleStore.personIsSelected(id: personId) ? .tGreen : .white).cornerRadius(geo.size.width / 2).frame(height: 70)
当我点击一个单元格时会发生以下情况:
class PeopleStore: ObservableObject {
@Published var people : [Person]
init(people: [Person]){
self.people = people
}
func personIsSelected(id: UUID) -> Bool {
let index = people.firstIndex(where: { $0.id == id })!
print("ZSTACK: \(people[index].name) is selected: \(people[index].isSelected.description)")
return people[index].isSelected
}
func toggleSelectionOfPerson(with id: UUID) {
let index = people.firstIndex(where: { $0.id == id })!
print("BEFORE \(people[index].name) is selected: \(people[index].isSelected.description)")
people[index].isSelected = !people[index].isSelected
print("AFTER \(people[index].name) is selected: \(people[index].isSelected.description)")
}
当我查看我的控制台时,您可以看到在我选择一个人后,视图会重新绘制,但它具有以前的值(在这种情况下,我点击了 Alexandra 单元格):
Tapped Cell: Alexandra R.
BEFORE Alexandra R. is selected: false
ZSTACK: Jose G. is selected: false
ZSTACK: Jimmy T. is selected: false
ZSTACK: Alexandra R. is selected: false
ZSTACK: Dominic R. is selected: false
AFTER Alexandra R. is selected: true
ZSTACK: Franny E. is selected: false
ZSTACK: Jon B. is selected: true
ZStack:在重新绘制单元格时打印。正如你所看到的,Alexandra 被选中:当我期望它为真时,出现了假。
重新抽签的时间似乎有点不对劲,而且似乎是随机的。我错过了什么?
编辑:人员结构
struct Person: Identifiable {
let id = UUID()
var name: String
var photo: Image
var isFavorite: Bool
var dateFavorited = Date()
var isSelected: Bool = false
}
编辑 2:如果有帮助,PersonCell 是一个名为 PersonList 的子视图,它使用 ForEach 生成 PersonCell。
struct PeopleList: View {
@EnvironmentObject var peopleStore: PeopleStore
var title: String {
return isFavorites ? "Favorites" : "All Employees"
}
var isFavorites: Bool
var body: some View {
LazyVStack(alignment: .leading, spacing: 15) {
Text(title).padding(.top, 18).padding(.horizontal, 5).font(.regular())
if isFavorites {
ForEach(peopleStore.people.sorted(by: { $0.dateFavorited < $1.dateFavorited }).filter({ $0.isFavorite })) { person in
PersonCell(personId: person.id).frame(height: 70.0)
}
解决方案
我不确定你到底出了什么问题,我已经测试了你的代码,它工作得很好。我所做的唯一更改是设置var isFavorites: Bool = true
,PeopleList
因为我不知道您如何在代码中切换该属性。所以,我为它提供了一个常量值。
下面是代码-:
struct Person: Identifiable {
let id = UUID()
var name: String
var photo: Image
var isFavorite: Bool
var dateFavorited = Date()
var isSelected: Bool = false
}
class PeopleStore: ObservableObject {
@Published var people : [Person]
init(people: [Person]){
self.people = people
}
func personIsSelected(id: UUID) -> Bool {
let index = people.firstIndex(where: { $0.id == id })!
print("ZSTACK: \(people[index].name) is selected: \(people[index].isSelected.description)")
return people[index].isSelected
}
func personName(id: UUID) -> String {
let index = people.firstIndex(where: { $0.id == id })!
return people[index].name
}
func toggleSelectionOfPerson(with id: UUID) {
let index = people.firstIndex(where: { $0.id == id })!
print("BEFORE \(people[index].name) is selected: \(people[index].isSelected.description)")
people[index].isSelected = !people[index].isSelected
print("AFTER \(people[index].name) is selected: \(people[index].isSelected.description)")
}
}
struct PeopleList: View {
@EnvironmentObject var peopleStore:PeopleStore
var title: String {
return isFavorites ? "Favorites" : "All Employees"
}
var isFavorites: Bool = true
var filteredPersons:[Person]{
peopleStore.people.sorted(by: { $0.dateFavorited < $1.dateFavorited }).filter({ $0.isFavorite })
}
var body: some View {
LazyVStack(alignment: .leading, spacing: 15) {
Text(title).padding(.top, 18)
if isFavorites {
ForEach(filteredPersons) { person in
PersonCell(personId: person.id).frame(height: 70.0)
}
}
}
}
}
struct PersonCell: View {
@EnvironmentObject var peopleStore:PeopleStore
var personId: UUID
var body: some View {
Button(action: {
print("Tapped Cell: " + peopleStore.personName(id: personId))
peopleStore.toggleSelectionOfPerson(with: personId)
}) {
GeometryReader { geo in
ZStack {
Rectangle().foregroundColor(peopleStore.personIsSelected(id: personId) ? .green : .gray).cornerRadius(geo.size.width / 2).frame(height: 70)
}
}
}
}
}
主视图-:
import SwiftUI
@main
struct Test: App {
@StateObject var store:PeopleStore
init() {
let person = Person(name: "foo", photo: Image(""), isFavorite: true)
let person1 = Person(name: "foo1", photo: Image(""), isFavorite: true)
let person2 = Person(name: "foo2", photo: Image(""), isFavorite: true)
let obj = PeopleStore(people: [person,person1,person2])
_store = StateObject(wrappedValue: obj)
}
var body: some Scene {
WindowGroup {
PeopleList().environmentObject(store)
}
}
}
输出-:
Tapped Cell: foo
BEFORE foo is selected: false
AFTER foo is selected: true
ZSTACK: foo2 is selected: false
ZSTACK: foo is selected: true
ZSTACK: foo1 is selected: false
注意-:我已经测试了多次,没有发现所选单元格不改变颜色的任何问题。
推荐阅读
- r - 如何将此垂直数据集转换为水平数据集?
- assembly - 如何计算汇编指令的时钟周期
- google-colaboratory - 从 Google Colab 的工作区本地下载文件会使用我的互联网还是 Colab 的互联网?
- java - 我使用从 maven 生成的 jar 通过 install4j 为我的应用程序创建了一个安装程序。为什么执行.exe时找不到主类?
- java - 使用 AOP 进行注释 - 在方法级别工作,而只有类被注释
- typescript - 在 typescript 中使用 SES 发送电子邮件
- flutter - 我们如何使用 Flutter 中的底部导航栏触发有状态小部件以通过导航重建自身?
- r - 我的 R 脚本在运行时完美运行,但是当我在 R markdown 中使用相同的脚本时,出现错误“当前工作目录中不存在”
- c - 计算错误,用+代替-
- javascript - 我正在创建一个聊天机器人来响应我需要一些特定的回复而不是单个关键字匹配