You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 10:15:09