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

LazyVGrid项.onTapGesture绑定后Sheet显示值异常问题

问题解决方法

你的问题出在SwiftUI的sheet(isPresented:)在循环中的捕获机制上:所有Text组件都绑定到同一个editActual状态变量,当你点击任意项触发editActual = true时,SwiftUI会重新计算视图,此时balance变量已经是循环遍历结束后的固定值,导致ActualBalanceView拿到的不是你点击的那个balance。

下面是两种可行的解决方式:

方式一:使用sheet(item:)绑定选中对象

这种方式更贴合SwiftUI状态管理逻辑,通过绑定可选的选中对象来展示sheet:

  1. 先定义一个可选状态变量存储选中的balance:
@State private var selectedBalance: Balance? // Balance为你的数据模型类型
  1. 修改LazyVGrid中的代码:
LazyVGrid(columns: columns) {
    ForEach(monthNames!, id: \.number) { month in
        Text(month.name)
    }
    ForEach(balances, id: \.id) { balance in
        Text(valueFormatter.string(from: balance.balance! as NSNumber)!)
            .onTapGesture {
                 print(balance.balance!)
                 selectedBalance = balance // 存储当前点击的对象
            }
            .sheet(item: $selectedBalance) { selected in
                ActualBalanceView(
                    show: Binding(
                        get: { selectedBalance != nil },
                        set: { if !$0 { selectedBalance = nil } }
                    ),
                    year: selectedYear,
                    month: selectedMonth,
                    balance: selected.balance! as Decimal
                )
            }
        }
}

注意:你的Balance模型需要遵循Identifiable协议;如果未遵循,可使用sheet(item:id:)并指定id的key path。

同时需要调整ActualBalanceView的关闭逻辑,让它能将selectedBalance置为nil来关闭sheet。

方式二:封装为独立子视图

把带点击和sheet的Text封装成独立子视图,让每个子视图拥有专属状态,避免捕获问题:

  1. 创建子视图:
struct BalanceItemView: View {
    let balance: Balance
    let selectedYear: Int // 替换为你的实际类型
    let selectedMonth: Int // 替换为你的实际类型
    let valueFormatter: NumberFormatter
    
    @State private var editActual = false
    
    var body: some View {
        Text(valueFormatter.string(from: balance.balance! as NSNumber)!)
            .onTapGesture {
                print(balance.balance!)
                editActual = true
            }
            .sheet(isPresented: $editActual) {
                ActualBalanceView(
                    show: $editActual,
                    year: selectedYear,
                    month: selectedMonth,
                    balance: balance.balance! as Decimal
                )
            }
    }
}
  1. 在原LazyVGrid中调用该子视图:
LazyVGrid(columns: columns) {
    ForEach(monthNames!, id: \.number) { month in
        Text(month.name)
    }
    ForEach(balances, id: \.id) { balance in
        BalanceItemView(
            balance: balance,
            selectedYear: selectedYear,
            selectedMonth: selectedMonth,
            valueFormatter: valueFormatter
        )
    }
}

两种方式都能解决问题,推荐第一种sheet(item:)的实现,更符合SwiftUI状态管理的最佳实践。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 21:10:45