SwiftUI .actionSheet内部变量无法更新 点击不同条目显示初始数据
问题根因
这是SwiftUI中基于isPresented控制的弹窗的常见问题,由两个原因共同导致:
- 所有列表条目共用同一个布尔类型的弹窗控制状态,系统无法区分当前触发弹窗对应的具体条目
isPresented版本的弹窗内容闭包会在视图首次渲染时完成变量捕获,后续状态变更不会更新捕获的变量值,因此永远展示第一次触发弹窗时的条目数据

修复方案
方案1:使用item版本的弹窗(推荐)
该方案通过可选类型的选中条目状态控制弹窗,系统会自动在选中条目更新时重新渲染弹窗内容,永远匹配最新选中的数据。
步骤1:新增状态变量
// 替换原有的@State var showActionSheet = false @State private var selectedRun: RunSourceSample?
步骤2:修改父视图布局代码
var body: some View { VStack { ForEach(sampleSourceData) { link in VStack { SampleView(day: link.day, distance: link.distance, exercise: link.exercise) { // 点击按钮时存储当前选中的条目 selectedRun = link } } } } // 将actionSheet移到列表外层,绑定到选中条目 .actionSheet(item: $selectedRun) { run in ActionSheet(title: Text("\(run.day): \(run.distance) \(run.exercise)"), message: Text("Stay Golden"), buttons: [ .cancel(), .default( Text("Action 1") ), .default( Text("Action 2") ) ] ) } }
步骤3:修改子视图的点击回调
struct SampleView: View { var day: String var distance: String var exercise: String // 替换原有的Binding,用闭包传递点击事件 var onTap: () -> Void var body: some View { HStack { Text(day) Text(distance) Text(exercise) Spacer() Button(action: { onTap() }) { Image(systemName: "ellipsis") } } .padding() .background(Color("BlueGray")) .cornerRadius(13) } }
方案2:将弹窗下放到子视图内部
每个子视图独立管理自己的弹窗状态,避免共用状态导致的数据错乱,修改成本更低。
直接修改SampleView代码即可,父视图不需要调整:
struct SampleView: View { var day: String var distance: String var exercise: String // 子视图自己持有弹窗状态,不需要外部传入Binding @State private var showActionSheet = false var body: some View { HStack { Text(day) Text(distance) Text(exercise) Spacer() Button(action: { showActionSheet = true }) { Image(systemName: "ellipsis") } } .padding() .background(Color("BlueGray")) .cornerRadius(13) // 弹窗移到子视图内部,直接使用当前子视图的属性即可拿到正确数据 .actionSheet(isPresented: $showActionSheet) { ActionSheet(title: Text("\(day): \(distance) \(exercise)"), message: Text("Stay Golden"), buttons: [ .cancel(), .default( Text("Action 1") ), .default( Text("Action 2") ) ] ) } } }
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

