对于 List-Detail 界面 - 数据在 Detail View 中更新,Data 更改但不会立即反映在 Detail 视图中 [英] For a List-Detail interface - Data is updated in the Detail View, and the Data is changed but not immediately reflected in the Detail view
问题描述
我在 Apple Watch 上使用 SwiftUI 并尝试正确使用 @ObservableObject、@ObservedObject 和 @Binding.我正在更新 DetailView 中的一个值,并且我希望它在本地得到反映,以及在全局范围内更改数据.下面的代码有效,但我使用 kludge 强制 DetailView 重绘自身:
I am using SwiftUI on the Apple Watch and trying to use @ObservableObject, @ObservedObject, and @Binding correctly. I'm updating a value in a DetailView, and I want to have it reflected locally, as well as have the data changed globally. The code below works, but I am using a kludge to force the DetailView to redraw itself:
有没有更好的方法?
-------------- ContentView.swift ---------------
-------------- ContentView.swift ---------------
import Combine
import SwiftUI
struct person: Identifiable {
var id:Int = 0
var name:String
init( id: Int, name:String) {
self.id = id
self.name = name
}
}
class AppData: ObservableObject {
@Published var people:[person] = [person(id:0, name:"John"),
person(id:1, name:"Bret"),
person(id:2,name:"Sue"),
person(id:3,name:"Amy")]
}
var gAppData = AppData()
struct ContentView: View {
@ObservedObject var model:AppData
var body: some View {
List( model.people.indices ){ index in
NavigationLink(destination: DetailView(person:self.$model.people[index])) { Text(self.model.people[index].name) }
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView(model:gAppData)
}
}
-------------- DetailView.swift ---------------
-------------- DetailView.swift ---------------
import SwiftUI
struct DetailView: View {
@Binding var person: person
// Created an unnecessary var to force a redreaw of the view
@State var doRedraw:Bool = true
var body: some View {
VStack(){
Text(person.name)
Button(action:{ self.person.name = "Bob"; self.doRedraw = false }) {
Text("Set Name to Bob")
}
}
}
}
struct DestView_Previews: PreviewProvider {
static var previews: some View {
DetailView(person:.constant(person( id:0, name:"John"))) // what does ".constant" actually do?
}
}
推荐答案
这里的问题是因为只有当您更改 @State
或 @Binding
变量时,您的视图才会重绘.这里你没有改变Person
变量,而是它的属性,它不应该影响用户界面(因为你没有说要这样做).我稍微更改了您的代码以展示如何实现此效果,您可以从这一点开始.您需要记住,究竟是什么影响了 UI:
The problem here is because your view redraws only when you changes the @State
or @Binding
variable. Here you do not change the Person
variable, but its property, which should not affect the user interface (because you didn't say to do this). I changed your code for a little for showing how to achieve this effect, you can go ahead from this point. You need to remember, what exactly affect UI:
class Person: Identifiable, ObservableObject { // better to assign struct/class names using UpperCamelCase
@Published var name:String // now change of this variable will affect UI
var id:Int = 0
init( id: Int, name:String) {
self.id = id
self.name = name
}
}
// changes in DetailView
struct DetailView: View {
@EnvironmentObject var person: Person
var body: some View {
VStack(){
Text(person.name)
Button(action:{ self.person.name = "Bob" }) {
Text("Set Name to Bob")
}
}
}
}
// preview
struct DetailViewWithoutGlobalVar_Previews: PreviewProvider {
static var previews: some View {
DetailView()
.environmentObject(Person(id: 1, name: "John"))
}
}
更新:列表和详细信息的完整代码
update: full code for List and Detail
import SwiftUI
class Person: Identifiable, ObservableObject { // better to assign type names using UpperCamelCase
@Published var name: String //{
var id: Int = 0
init( id: Int, name:String) {
self.id = id
self.name = name
}
func changeName(_ newName: String) {
self.name = newName
}
}
class AppData: ObservableObject {
@Published var people: [Person] = [Person(id:0, name:"John"),
Person(id:1, name:"Bret"),
Person(id:2,name:"Sue"),
Person(id:3,name:"Amy")]
}
struct ContentViewWithoutGlobalVar: View {
@EnvironmentObject var model: AppData
var body: some View {
NavigationView { // you forget something to navigate between views
List(model.people.indices) { index in
NavigationLink(destination: DetailView()
.environmentObject(self.model.people[index])) {
PersonRow(person: self.$model.people[index])
}
}
}
}
}
struct PersonRow: View {
@Binding var person: Person // this struct will see changes in Person and show them
var body: some View {
Text(person.name)
}
}
struct DetailView: View {
@EnvironmentObject var person: Person
var body: some View {
VStack(){
Text(self.person.name)
Button(action:{ self.person.changeName("Bob") }) {
Text("Set Name to Bob")
}
}
}
}
struct ContentViewWithoutGlobalVar_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentViewWithoutGlobalVar()
.environmentObject(AppData())
DetailView()
.environmentObject(Person(id: 0, name: "John"))
}
}
}
这篇关于对于 List-Detail 界面 - 数据在 Detail View 中更新,Data 更改但不会立即反映在 Detail 视图中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!