首页 > 解决方案 > SwiftUI - 为 UI 切换动态添加 @State

问题描述

我目前正在从 Firebase Firestore 获取网站列表,然后将它们返回到 SwiftUI 中的列表。每个列表项都有一个标签和切换。站点列表是动态的,因此可以是 1-30 多个。如何创建 @State 或类似的可绑定对象来观察每个切换的状态。

我目前正在使用以下内容渲染到 UI

@State private var SiteA = false
Form {
     Section (header: Text("Select Sites")) {
     ForEach(siteData.sites) { site in
         HStack {
             Toggle(isOn: self.$SiteA) {
                 Text(site.name)
                 Spacer()
             }
         }
     }
     }
}

使用 Bindable 对象检索站点

import SwiftUI
import Combine
import Firebase
import FirebaseFirestore

struct Message: Identifiable {
    var title: String
    var messageBody: String
    var sentBy: String
    var targetSite: String
    var expired: Bool
    var timeStamp: Timestamp
    var emergency: Bool
    var id: String
}

struct Site: Identifiable {
    var id: String
    var name: String
}

class FirestoreMessages : ObservableObject {
    var db = Firestore.firestore()
    var didChange = PassthroughSubject<FirestoreMessages, Never>()
    @Published var messages: [Message] = [] {
        didSet{ didChange.send(self) }
    }
    @Published var sites: [Site] = [] {
        didSet { didChange.send(self) }
    }

    func listen() {
        db.collection("messages")
            .whereField("expired", isEqualTo: false)
            .addSnapshotListener { (snap, error) in
            if error != nil {
                print("Firebase Snapshot Error: \(error?.localizedDescription ?? "")")
            } else {

                self.messages.removeAll()

                for doc in snap!.documents {
                    let title = doc["title"] as! String
                    let messageBody = doc["body"] as! String
                    let sentBy = doc["sentBy"] as! String
                    let targetSite = doc["targetSite"] as! String
                    let expired = doc["expired"] as! Bool
                    let timeStamp = doc["timeStamp"] as! Timestamp
                    let emergency = doc["emergency"] as! Bool
                    let id = doc.documentID

                    let message = Message(
                        title: title,
                        messageBody: messageBody,
                        sentBy: sentBy,
                        targetSite: targetSite,
                        expired: expired,
                        timeStamp: timeStamp,
                        emergency: emergency,
                        id: id)

                    self.messages.append(message)
                }
            }
        }
    }

    func getSites() {
        db.collection("sites")
            .order(by: "name", descending: false)
            .getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting docs: \(err)")
            } else {
                self.sites.removeAll()

                for document in querySnapshot!.documents {
                    let doc = document.data()

                    let id = document.documentID
                    let name = doc["name"] as! String

                    let site = Site(id: id, name: name)

                    self.sites.append(site)
                }
            }
        }
    }
}

如何@State为每个列表项创建一个唯一项以单独监视它们的状态?

标签: swiftswiftui

解决方案


你的问题的答案是作文。将 HStack 和封闭的 Toggle 移动到 SiteRow 视图,其中每一行都有自己的状态。

struct SiteRow: View {

    @State private var state: Bool = false
    private let site: Site

    init(_ site: Site) {
        self.site = site
        self.state = site.isOn
    }

    var body: some View {
        HStack {
            Toggle(isOn: self.$state) {
                Text(site.name)
                Spacer()
            }
        }
    }
}

然后...

ForEach(siteData.sites) { site in SiteRow(site) }

推荐阅读