简体   繁体   English

SwiftUI 绑定到数组中的@ObservableObject

[英]SwiftUI Bind to @ObservableObject in array

How do I pass a bindable object into a view inside a ForEach loop?如何将可绑定的 object 传递到 ForEach 循环内的视图中?

Minimum reproducible code below.下面的最小可重现代码。

class Person: Identifiable, ObservableObject {
    let id: UUID = UUID()
    @Published var healthy: Bool = true
}


class GroupOfPeople {
    let people: [Person] = [Person(), Person(), Person()]
}

public struct GroupListView: View {
    
    //MARK: Environment and StateObject properties
    
    //MARK: State and Binding properties
    
    //MARK: Other properties
    let group: GroupOfPeople = GroupOfPeople()
    
    //MARK: Body
    public var body: some View {
        ForEach(group.people) { person in
            //ERROR: Cannot find '$person' in scope
            PersonView(person: $person)
        }
    }
    
    //MARK: Init
    
}

public struct PersonView: View {
    
    //MARK: Environment and StateObject properties
    
    //MARK: State and Binding properties
    @Binding var person: Person
    //MARK: Other properties
    
    
    //MARK: Body
    public var body: some View {
        switch person.healthy {
        case true:
            Text("Healthy")
        case false:
            Text("Not Healthy")
        }
    }
    
    //MARK: Init
    init(person: Binding<Person>) {
        self._person = person
    }
}

The error I get is Cannot find '$person' in scope .我得到的错误是Cannot find '$person' in scope I understand that the @Binding part of the variable is not in scope while the ForEach loop is executing.我知道在执行 ForEach 循环时,变量的 @Binding 部分不在 scope 中。 I'm looking for advice on a different pattern to accomplish @Binding objects to views in a List in SwiftUI.我正在寻找关于不同模式的建议,以完成 @Binding 对象到 SwiftUI 列表中的视图。

The SwiftUI way would be something like this: SwiftUI 方式是这样的:

// struct instead of class
struct Person: Identifiable {
    let id: UUID = UUID()
    var healthy: Bool = true
}


// class publishing an array of Person
class GroupOfPeople: ObservableObject {
    @Published var people: [Person] = [
        Person(), Person(), Person()
    ]
}

struct GroupListView: View {
    
    // instantiating the class
    @StateObject var group: GroupOfPeople = GroupOfPeople()
    
    var body: some View {
        List {
            // now you can use the $ init of ForEach
            ForEach($group.people) { $person in
                PersonView(person: $person)
            }
        }
    }
}

struct PersonView: View {
    
    @Binding var person: Person

    var body: some View {
        HStack {
            // ternary instead of switch
            Text(person.healthy ? "Healthy" : "Not Healthy")
            Spacer()
            // Button to change, so Binding makes some sense :)
            Button("change") {
                person.healthy.toggle()
            }
        }
    }
}

You don't need Binding .你不需要Binding You need ObservedObject .你需要ObservedObject

for anyone still wondering... it looks like this has been added对于仍然想知道的人......看起来已经添加了

.onContinuousHover(perform: { phase in
    switch phase {
    case .active(let location):
        print(location.x)
    case .ended:
        print("ended")
    }
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM