SwiftUI点击MainView按钮触发ListRowView子视图updatePoints方法实现问询
解决方案
你的触发思路是可行的,现有代码主要存在数据流向错误、状态监听缺失、属性包装器使用错误三类问题,修正方案如下:
核心改动点
- 修正数据绑定:Player实例需要用
@Binding包装,确保子视图修改积分后能同步到父视图的Game模型 - 状态职责拆分:每行独立的加减状态下沉到ListRowView内部,不要放在父视图全局共享
- 补充状态监听:使用SwiftUI内置的
onChange修饰符监听触发标记的变化,自动执行积分更新逻辑 - 移除子视图对全局触发标记的修改,避免多实例同时修改状态混乱
修正后完整代码
MainView.swift
struct MainView: View { @Binding var game : Game @State private var invokeFunction : Bool = false var body: some View { NavigationView { List { Section { // 遍历绑定数组,给子视图传递可修改的Player绑定 ForEach($game.players, id: \.self) { $player in ListRowView(invokeFunction: $invokeFunction, player: $player) } } Button(action: { invokeFunction.toggle() }) { Text("Calculate") } } } } }
ListRowView.swift
struct ListRowView: View { @Binding var invokeFunction : Bool @Binding var player : Player // 每行独立的加减状态 @State private var addingPoints : Bool = true // 补充原来缺失的输入框文本状态 @State private var inputText = "" var body: some View { HStack { Text(player.name) Spacer() Text("\(player.points)") Spacer() Button(action: { addingPoints.toggle() }) { if addingPoints { Image(systemName: "plus.circle.fill") .foregroundColor(.green) } else { Image(systemName: "minus.circle.fill") .foregroundColor(.red) } }.buttonStyle(BorderlessButtonStyle()) TextField("0", text: $inputText) .keyboardType(.numberPad) } // 监听触发标记变化,执行积分更新逻辑 .onChange(of: invokeFunction) { _ in updatePoints() } } private func updatePoints() { let newPoints = Int(inputText) ?? 0 guard newPoints != 0 else { return } if addingPoints { player.points += newPoints print("加积分 \t 旧积分: \(player.points - newPoints) - 新积分: \(player.points)") } else { player.points -= newPoints print("减积分 \t 旧积分: \(player.points + newPoints) - 新积分: \(player.points)") } // 可选操作:执行完成后清空输入框 inputText = "" } }
原有Player结构体无需修改。
内容的提问来源于stack exchange,提问作者user12631628
相关产品推荐
相关产品推荐

