如何为SwiftUI网格中的Button分配可点击引用的属性
SOS游戏网格按钮属性分配与点击处理方案
问题背景
开发SOS游戏项目,需实现可切换3x3至10x10尺寸的网格按钮。现有网格布局代码,已定义存储按钮属性的buttonData结构体,需求为每个网格按钮分配该属性并在点击时引用。此前尝试State、StateObject仅生成单个实例,onAppear中分配的属性无法在Button的action闭包中调用。
现有核心代码:
网格布局代码
Grid(horizontalSpacing: 0, verticalSpacing: 0) { ForEach(0..<boardSize, id: \.self) { row in GridRow { ForEach(0..<boardSize, id: \.self) { col in GeometryReader { gridCellSize in Rectangle() .foregroundColor(.teal) .overlay(Text("\(row),\(col)").fontWeight(.heavy)) .border(Color.black) Button { } label: { Text("") .frame(width: gridCellSize.frame(in: .global).width , height: gridCellSize.frame(in: .global).height) } } } } } }
按钮属性结构体
struct buttonData { var buttonID = UUID() var buttonContents: String var buttonCoords: (buttonX: Int, buttonY: Int) }
解决方案
1. 重构buttonData结构体
让结构体遵循Identifiable协议,适配SwiftUI的ForEach遍历逻辑,同时修正命名规范:
struct ButtonData: Identifiable { let id = UUID() var contents: String var coords: (x: Int, y: Int) }
2. 用@State管理按钮状态数组
在视图中添加@State变量存储所有按钮数据,通过onChange监听boardSize变化,动态生成对应尺寸的按钮数组:
@State private var buttons: [ButtonData] = [] @State private var boardSize = 3 // 默认3x3网格 // 监听网格尺寸变化,重新初始化按钮数组 .onChange(of: boardSize) { newSize in buttons = (0..<newSize).flatMap { row in (0..<newSize).map { col in ButtonData(contents: "", coords: (x: col, y: row)) } } }
3. 修改网格布局,绑定按钮数据
将原双层ForEach改为通过索引关联按钮数组,在Button的action闭包中直接访问对应按钮属性:
Grid(horizontalSpacing: 0, verticalSpacing: 0) { ForEach(0..<boardSize, id: \.self) { row in GridRow { ForEach(0..<boardSize, id: \.self) { col in let index = row * boardSize + col let currentButton = buttons[index] GeometryReader { gridCellSize in Rectangle() .foregroundColor(.teal) .overlay(Text("\(currentButton.coords.y),\(currentButton.coords.x)") .fontWeight(.heavy)) .border(Color.black) Button { // 点击时直接引用按钮属性 print("点击按钮:ID=\(currentButton.id),坐标=\(currentButton.coords)") // 若需修改按钮内容,通过更新数组同步状态 var updatedButtons = buttons updatedButtons[index].contents = "S" // 示例修改内容 buttons = updatedButtons } label: { Text(currentButton.contents) .frame(width: gridCellSize.size.width, height: gridCellSize.size.height) .foregroundColor(.black) } } } } } }
关键说明
- 通过
row * boardSize + col计算数组索引,确保每个网格位置对应唯一的ButtonData实例 @State数组存储所有按钮状态,保证状态更新时视图自动刷新- 点击按钮时可直接访问当前按钮的
id、coords、contents属性,修改内容时通过更新数组实现状态同步
内容的提问来源于stack exchange,提问作者user18176479
相关产品推荐
相关产品推荐

