用MainView布尔值调用Subview函数



我正在拼命尝试以下内容:

我在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

最新更新