如何解决使用核心数据绑定编辑TextField时不会触发“ .disabled”修饰符
我正在开发一个游戏,玩家(本地)需要向队友描述一个数字单词,而后者又会在给定的时限内猜测尽可能多的单词。这意味着我必须让他们创建团队并向这些团队添加玩家。
我已经设置了核心数据并创建了一个SwiftUI视图,用于创建团队并向这些团队添加玩家:这是可行的。我现在正在构建一个视图,用于编辑团队属性,但是我正在努力使用.disabled修饰符进行数据验证。我想确保在少于2人的团队中,并且任何字段(团队名称或球员名称)为空时,禁用“保存”按钮。
发生的事情是,在编辑团队名称(团队实体的直接属性)时,我的.disabled修饰符会按计划触发,因此我可以检查它是否为空。但是,在编辑任何播放器名称时,传递给.disabled修饰符的函数不会不触发,因此我无法检查播放器名称是否为空。
下面是我的代码:
struct EditTeamsView: View {
@Environment(\.presentationMode) var presentationMode
@Environment(\.managedobjectContext) var managedobjectContext
@Observedobject var existingTeam: Team
var body: some View {
ZStack {
Color.init(UIColor.systemGroupedBackground)
.edgesIgnoringSafeArea(.all)
vstack {
Form {
// Team name textfield
Section(footer: Text("A team needs a minimum of 2 players,and can have a maximum of 5 players.")) {
TextField("Team name...",text: $existingTeam.name ?? "")
}
Section {
ForEach(existingTeam.playerArray,id: \.self) { player in
TextField("Player name...",text: Binding(
get: {
player.wrappedname
},set: { newValue in
player.name = newValue
}))
}
.onDelete(perform: deletePlayers)
}
}
StockFullWidthButton(action: {
saveChanges()
self.presentationMode.wrappedValue.dismiss()
},label: "Save Changes")
.disabled(!isInputValid())
}
}
.navigationBarTitle("Edit Team",displayMode: .inline)
}
func deletePlayers(at offsets: IndexSet) {
for index in offsets {
let playerToRemove = existingTeam.playerArray[index]
existingTeam.removeFromPlayers(playerToRemove)
}
}
func isInputValid() -> Bool {
print("Input is checked")
guard !existingTeam.name!.isEmpty else { return false }
guard existingTeam.playerArray.count >= 2 else { return false }
for player in existingTeam.playerArray {
if player.name!.isEmpty {
return false
}
}
return true
}
func saveChanges() {
if managedobjectContext.hasChanges {
try? self.managedobjectContext.save()
}
}
}
对于团队名称TextField绑定,我使用了此运算符重载(取自another post on SO)。这对于球队名称文本字段效果很好,但不适用于球员名称。
func ??<T>(lhs: Binding<Optional<T>>,rhs: T) -> Binding<T> {
Binding(
get: { lhs.wrappedValue ?? rhs },set: { lhs.wrappedValue = $0 }
)
}
这就是为什么我对玩家名称文本字段使用自定义绑定的原因:
Binding(get: { player.wrappedname },set: { newValue in player.name = newValue })
关于如何解决此问题的任何想法?预先感谢!
解决方法
如果要在某些条件下更新视图,则需要具有明确的状态并手动管理该状态。在提供的代码中,您依赖于该视图将在刷新时进行验证,但是刷新不会发生,因为未更改任何依赖关系。
这里是可能的解决方案-为错误的输入提供明确的状态,并在所需条件发生变化时明确触发它
@ObservedObject var existingTeam: Team
@State private var isBadInput = false // << this !!
var body: some View {
ZStack {
Color.init(UIColor.systemGroupedBackground)
.edgesIgnoringSafeArea(.all)
VStack {
Form {
// Team name textfield
Section(footer: Text("A team needs a minimum of 2 players,and can have a maximum of 5 players.")) {
TextField("Team name...",text: $existingTeam.name ?? "")
.onReceive(existingTeam.$name) { _ in
self.isBadInput = !isInputValid() // << updated !!
}
}
Section {
ForEach(existingTeam.playerArray,id: \.self) { player in
TextField("Player name...",text: Binding(
get: {
player.wrappedName
},set: { newValue in
player.name = newValue
}))
.onReceive(player.objectWillChange) { _ in
self.isBadInput = !isInputValid() // << updated !!
}
}
.onDelete(perform: deletePlayers)
}
}
StockFullWidthButton(action: {
saveChanges()
self.presentationMode.wrappedValue.dismiss()
},label: "Save Changes")
.disabled(isBadInput) // << used !!
}
}
.navigationBarTitle("Edit Team",displayMode: .inline)
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。