使用 MainView 布尔值调用 Subview 函数
Call Subview function with MainView boolean
我正在拼命尝试以下操作:
我在 MainView 中有一个 ForEach 循环,其中包含不同数量的 ListRowView。此 ListRowView 包含一个带 player.name 和 player.points 的 HStack 以及一个 TextField,玩家可以在其中写入一个数字,然后将其相加或相减。
在按下 MainView 中的“计算”按钮后的 ListRowView 中,应该调用函数 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")
}
})
}
}
}
}
}
}
这里是(子视图)ListRowView,应该在其中调用 func 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")
}
})
}
}
}
}
这样,每当 'game' 对象在 calculateAllPlayers
函数中被修改时,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
我正在拼命尝试以下操作:
我在 MainView 中有一个 ForEach 循环,其中包含不同数量的 ListRowView。此 ListRowView 包含一个带 player.name 和 player.points 的 HStack 以及一个 TextField,玩家可以在其中写入一个数字,然后将其相加或相减。
在按下 MainView 中的“计算”按钮后的 ListRowView 中,应该调用函数 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")
}
})
}
}
}
}
}
}
这里是(子视图)ListRowView,应该在其中调用 func 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")
}
})
}
}
}
}
这样,每当 'game' 对象在 calculateAllPlayers
函数中被修改时,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