我正在拼命尝试以下内容:
我在MainView中有一个ForEach循环,其中包含不同数量的ListRowView。这个ListRowView包含一个带有player.name和player的HStack。分数和一个TextField,玩家可以在其中写下一个数字,它将被求和或减去。
在ListRowView中按下&;calculate&;按钮在MainView函数updatePoints()应该被调用,但在这里我失败了(我尝试了didSet和willSet)。有人知道如何最好地实现这一点吗?
感谢struct MainView: View {
//Binding
@Binding var game : Game
//for Changing the Points
@State private var addingPoints : Bool = true
@State private var invokeFunction : Bool = false
var body: some View {
VStack{
let players : [Player] = game.players
NavigationView{
VStack{
List{
Section(){
ForEach(players, id: .self){
player in
ListRowView(invokeFunction: $invokeFunction, addingPoints: addingPoints, player: player)
}
}
Button(action: {
invokeFunction.toggle()
}, label: {
Text("Calculate")
}
})
}
}
}
}
}
}
这里是(Subview) ListRowView,其中函数updatePoints()应该被调用。
struct ListRowView: View {
@Binding var invokeFunction : Bool
@State var addingPoints : Bool
@State var player : Player
var body: some View {
HStack{
Text("(player.name)")
Spacer()
Text("(player.points)")
Spacer()
//add or delete number from points
Button(action: {
addingPoints.toggle()
}){
if(addingPoints){
Image(systemName: "plus.circle.fill")
.foregroundColor(.green)
} else {
Image(systemName: "minus.circle.fill")
.foregroundColor(OwnColor.ownRed)
}
}.buttonStyle(BorderlessButtonStyle())
//added new points with own TextField
TextField("0", text: $limitTextField.text)
.keyboardType(.numberPad)
}
}
mutating func updatePoints(add: Bool) -> Void {
var newPoints = 0
if self.invokeFunction {
if (limitTextField.text.isEmpty) {
self.player.points += newPoints
} else {
newPoints = Int(limitTextField.text) ?? 0
if (add) {
self.player.points += newPoints
print("Add t Old points: (player.points - newPoints) - New Points: (player.points)")
} else {
self.player.points -= newPoints
print("Sub t Old points: (player.points + newPoints) - New Points: (player.points)")
}
}
}
invokeFunction.toggle()
}
}
这里还有一个Player结构体
struct Player : Identifiable, Codable, Hashable{
let id : UUID
var name : String
var points : Int
var hashValue: Int {
return name.hashValue
}
}
在你的MainView
中使用@Binding与游戏变量
var body: some View {
//Remove this
//let players : [Player] = game.players
NavigationView{
VStack{
List{
Section(){
ForEach($game.players, id: .self){
player in
ListRowView(invokeFunction: $invokeFunction, addingPoints: addingPoints, player: player)
}
}
Button(action: {
calculateAllPlayers()
}, label: {
Text("Calculate")
}
})
}
}
}
}
这样,每当在calculateAllPlayers
函数中修改'game'对象时,ForEach就会动态地更新玩家,您将得到如下内容
func calculateAllPlayers(add: Bool) -> Void {
for player in game.players {
//do your calulations here modifying the 'player' object
}
}
在子视图中,你可以从播放器变量中删除@State并添加@Binding
编辑:我在这里添加了另一种可能性,因为OP指定他不能从主视图访问数据。
你也可以在子视图上添加。onchange (of),如下
HStack{
Text("(player.name)")
//....
}
.onChange(of: invokeFunction) {
if invokeFunction {
//call your function
}
}
每次of
状态改变时调用onChange