SwiftUI首次点击卡片弹出FullScreenCover无数据问题求助
问题原因与解决方案
核心问题
- 重复绑定模态视图:你在
ForEach循环内给每个Button都添加了fullScreenCover,所有模态都绑定同一个showSheet状态。这会导致SwiftUI创建多份模态实例,首次触发时容易出现状态更新和视图加载的时序冲突。 - 状态更新时序问题:首次点击时,
showSheet = true会立即触发模态展示,但selectedGoal = goal的状态更新可能还没完成,此时Modal拿到的还是初始空的Goal实例,所以显示无数据。
修复方案(推荐)
改用fullScreenCover(item:)的方式,通过可选类型的选中目标来控制模态展示,这种方式能确保模态展示时,选中的数据已经完全赋值:
import SwiftUI struct GoalsView: View { @Binding var rootActive: Bool @Binding var addGoalIsClicked: Bool // 改为可选类型,初始为nil @State private var selectedGoal: Goal? var body: some View { ScrollView { VStack(){ HStack{ Text("Add goals") .fontWeight(.bold) .font(.system(size: 28)) Spacer() } .padding() ForEach(goalDB) {goal in Button() { // 直接赋值选中的目标,触发模态展示 selectedGoal = goal }label: { Label(goal.title, systemImage: "") .frame(maxWidth: .infinity) .foregroundColor(.black) } .padding() .background { RoundedRectangle(cornerRadius: 10) .frame(maxWidth: .infinity) .foregroundColor(.white) } } .padding(4) } } // 将fullScreenCover移到循环外部,整个视图只保留一个模态 .fullScreenCover(item: $selectedGoal) { selectedItem in ModalView(rootActive: $rootActive, goal: selectedItem) } .background(Color.gray.opacity(0.15)) } } // 需要让Goal遵循Identifiable协议(如果还没的话) extension Goal: Identifiable {}
另一种修复方式(基于原状态逻辑调整)
如果不想修改状态类型,也可以把fullScreenCover移到循环外部,确保只有一个模态实例,同时通过延迟触发确保状态先更新再展示:
import SwiftUI struct GoalsView: View { @Binding var rootActive: Bool @State private var showSheet = false @Binding var addGoalIsClicked: Bool @State private var selectedGoal : Goal = Goal(title: "", description: "") var body: some View { ScrollView { VStack(){ HStack{ Text("Add goals") .fontWeight(.bold) .font(.system(size: 28)) Spacer() } .padding() ForEach(goalDB) {goal in Button() { selectedGoal = goal // 延迟触发,确保状态更新完成后再展示模态 DispatchQueue.main.async { showSheet = true } }label: { Label(goal.title, systemImage: "") .frame(maxWidth: .infinity) .foregroundColor(.black) } .padding() .background { RoundedRectangle(cornerRadius: 10) .frame(maxWidth: .infinity) .foregroundColor(.white) } } .padding(4) } } // 移到外部 .fullScreenCover(isPresented: $showSheet) { ModalView(rootActive: $rootActive, goal: selectedGoal) } .background(Color.gray.opacity(0.15)) } }
说明
第一种方案(item:绑定)是SwiftUI官方推荐的方式,它直接将模态展示与选中的数据绑定,从根源上避免了时序问题,代码也更简洁。
内容的提问来源于stack exchange,提问作者Stusio
相关产品推荐
相关产品推荐

