LazyVGrid项.onTapGesture绑定后Sheet显示值异常问题
问题解决方法
你的问题出在SwiftUI的sheet(isPresented:)在循环中的捕获机制上:所有Text组件都绑定到同一个editActual状态变量,当你点击任意项触发editActual = true时,SwiftUI会重新计算视图,此时balance变量已经是循环遍历结束后的固定值,导致ActualBalanceView拿到的不是你点击的那个balance。
下面是两种可行的解决方式:
方式一:使用sheet(item:)绑定选中对象
这种方式更贴合SwiftUI状态管理逻辑,通过绑定可选的选中对象来展示sheet:
- 先定义一个可选状态变量存储选中的balance:
@State private var selectedBalance: Balance? // Balance为你的数据模型类型
- 修改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封装成独立子视图,让每个子视图拥有专属状态,避免捕获问题:
- 创建子视图:
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 ) } } }
- 在原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
相关产品推荐
相关产品推荐

