首页 > 解决方案 > 如何在 SwiftUI 中绑定计算属性

问题描述

我有一个简单的模型声明:

struct Claim: Codable, Identifiable {
    let id: String
    var name: String

    var isSelected: Bool? = nil // used for selecting claims in a list
}

AddClaimView 用于过滤掉已经存储role.claimsrole.

struct AddClaimView: View {
    var claims: [Claim] // all possible claims
    @Binding var role: Role
    var claimsForAdding: [Claim] {
        self.claims.filter { claim in
            !self.role.claims.contains(claim)
        }
    }
    var body: some View {
        VStack {
            Text("Add claim")
                .font(.largeTitle)
            ClaimsListRows(claims: self.claimsForAdding.sorted())
        }
    }
}

过滤是由计算属性完成的claimsForAdding,问题就来了。如何将计算属性绑定claimsForAdding到视图@Binding var claimsClaimsListRow,然后将它们添加到role.claims

@State var claimsForAdding....显然不适用于计算属性。

struct ClaimsListRows: View {
    @Binding var claims: [Claim]
    var body: some View {
        List(claims) { claim in
// set property isSelected = true when tapping a row
.....

在工作表中呈现的视图AddClaimView

struct RoleDetailed: View {
    @Binding var role: Role
    @State var showAddClaim = false
    @Binding var claims: [Claim]

    var body: some View {
       VStack(alignment: .leading) {
            HStack {
                Text(role.name)
                    .font(.largeTitle)
                Spacer()
            }
            Text("id: " + role.id)
                .font(.footnote)
                .foregroundColor(Color.gray)
            List {
                ForEach(role.claims) { claim in
                    ClaimRow(claim: claim)
                }
            }
        }.font(.headline).padding(10)
        .navigationBarItems(trailing:
            Button(action: {
                self.showAddClaim.toggle()
            }) {
                Text("Add claim")
            }.sheet(isPresented: self.$showAddClaim, onDismiss: {
                print("dismissed")
            }, content: {
                AddClaimView(claims: self.claims, role: self.$role)
            })
        )
    }

}

根据我收到的评论,这是新的AddClaimView

struct AddClaimView: View {
    var claims: [Claim]
    @Binding var role: Role
    var claimsForAdding: [Claim] {
        get {
            self.claims.filter { claim in
                !self.role.claims.contains(claim)
            }
        }
        set {
            var claims = self.claims
            claims.removeAll(where: { claim in
                newValue.contains(claim)
            })
        }
    }
    var body: some View {
        VStack {
            Text("Add claim")
                .font(.largeTitle)
            ClaimsListRows(claims: Binding<[Claim]>(
                get: {
                    self.claims.filter {
                        claim in !self.role.claims.contains(claim)
                    }
                    .sorted(by: { $0.name < $1.name })
                },
                set: { newValue in
                    var claims = self.claims
                    claims.removeAll(where: { claim in
                        newValue.contains(claim)
                    })
                    self.role.claims = claims
                }
            ))
        }
    }
}

标签: bindingswiftui

解决方案


您需要创建一个Binding更新角色的自定义:

ClaimsListRows(claims: Binding<[Claim]>(
    get: {
        self.claims.filter {
            claim in !self.role.claims.contains(claim)
        }
        .sorted(by: { $0.name < $1.name })
    },
    set: { newValue in
        var claims = self.claims
        claims.removeAll(where: { claim in
            newValue.contains(claim)
        })
        self.role.claims = claims
    }
))

推荐阅读