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

SwiftUI中仅更新选中GridItem状态值的问题

解决LazyVGrid中单个GridItem独立切换状态的问题

你当前的问题核心是所有GridItem共享了同一个isRed状态变量,所以切换时会全局同步。要实现单个条目独立控制,需要给每个GridItem单独维护状态,具体修改如下:

步骤1:改用字典存储每个条目的状态

把原来的单个@State var isRed换成字典,用条目ID作为键,对应每个条目的isRed状态:

@State private var itemStates: [Int: Bool] = [:]

字典的好处是可以按需存储每个条目的状态,不用提前初始化1092个值,后续通过default: false会自动处理未初始化的条目。

步骤2:修改GridItemView的绑定逻辑

在ForEach中,给每个GridItemView绑定对应ID的字典值,而非全局的isRed:

GridItemView(id: gridItemIndex, isRed: $itemStates[gridItemIndex, default: false])

这里的default: false表示如果字典里还没有该ID的记录,就默认使用false,同时会自动把这个键值对添加到字典中。

步骤3:修复ContextMenu的操作逻辑

直接切换对应ID的状态即可,无需通过视图对象访问属性(视图对象的属性不应直接修改,要通过绑定):

Button(action: {
    $itemStates[gridItemIndex, default: false].wrappedValue.toggle()
}) {
    Label("Toggle isRed for gridItemIndex \(gridItemIndex)", systemImage: "paintbrush.fill")
}

修改后的完整代码

GridItemView(无需修改,保持原样)

import SwiftUI

struct GridItemView: View {
    var id: Int
    @Binding var isRed: Bool
    
    var body: some View {
        VStack {
            Text("Hello")
            Image(systemName: "globe.europe.africa")
        }
        .foregroundStyle(isRed ? .red : .black)
        .padding()
        .border(.black)
    }
}

修改后的ContentView

import SwiftUI

struct ContentView: View {
    let gridLayout = Array(repeating: GridItem(.flexible(), spacing: 0), count: 4)
    let numberOfGridItems = 1092
    
    // 用字典存储每个条目的独立状态
    @State private var itemStates: [Int: Bool] = [:]
    
    var body: some View {
        VStack {
            ScrollView(.vertical) {
                LazyVGrid(columns: gridLayout) {
                    ForEach(0..<numberOfGridItems, id: \.self) { gridItemIndex in
                        GridItemView(id: gridItemIndex, isRed: $itemStates[gridItemIndex, default: false])
                            .contextMenu {
                                Button(action: {
                                    // 直接切换对应ID的状态
                                    $itemStates[gridItemIndex, default: false].wrappedValue.toggle()
                                }) {
                                    Label("Toggle isRed for gridItemIndex \(gridItemIndex)", systemImage: "paintbrush.fill")
                                }
                            }
                    }
                }
                .scrollTargetLayout()
            }
            .scrollTargetBehavior(.viewAligned)
        }
    }
}

原理说明

通过字典itemStates,每个GridItem的ID对应唯一的isRed状态,切换时只会修改当前ID对应的键值对,不会影响其他条目。SwiftUI的绑定机制会自动监听字典的变化,只刷新状态改变的那个GridItem,同时LazyVGrid的视图复用特性也能保证性能不受影响。

内容的提问来源于stack exchange,提问作者RyanTCB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:16:18