SwiftUI中Foreach绑定Sheet在索引4后无法弹出求助
问题分析与解决方案
核心问题原因
你的问题出在LazyVStack的懒加载特性与Sheet修饰符的作用范围上。每个CalendarMonthView都自带.sheet修饰符,而LazyVStack会在视图滚出屏幕时销毁对应的子视图(比如4月及以后的月份视图)。当你滚动回去点击日期气泡时,虽然isSheetPresenting被设为true,但由于视图可能被重新初始化,SwiftUI的视图状态跟踪出现异常,导致Sheet无法正确弹出。
修复步骤
将Sheet的管理逻辑从子视图CalendarMonthView移到父视图YearView中,让父视图统一处理Sheet的展示:
- 修改
YearView,添加用于控制Sheet的状态变量:
struct YearView: View { @State private var createSheetDate: Date? @State private var editSheetDay: CalendarDay? var body: some View { ScrollViewReader { value in ScrollView { LazyVStack(alignment: .leading,spacing: 0, pinnedViews: [.sectionHeaders]) { ForEach(0..<12) { val in Section(header: SectionHeaderView(month: val + 1)) { CalendarMonthView( month: val + 1, year: getYearNumber(date: Date.now), onCreateTap: { date in createSheetDate = date }, onEditTap: { day in editSheetDay = day } ) .padding() } } } } } .sheet(item: $createSheetDate) { date in DayCreateView(date: .constant(date)) } .sheet(item: $editSheetDay) { day in DayEditView(day: day) } .navigationBarTitle(Text(""), displayMode: .inline) } }
- 修改
CalendarMonthView,移除内部的Sheet修饰符,通过回调将点击事件传递给父视图:
struct CalendarMonthView: View { @Query(sort: \CalendarDay.date) var days: [CalendarDay] var month: Int var year: Int let onCreateTap: (Date) -> Void let onEditTap: (CalendarDay) -> Void init(month: Int, year: Int, onCreateTap: @escaping (Date) -> Void, onEditTap: @escaping (CalendarDay) -> Void) { self.month = month self.year = year self.onCreateTap = onCreateTap self.onEditTap = onEditTap _days = Query( filter: #Predicate<CalendarDay> { day in day.monthNumber == month && day.yearNumber == year }, sort: \CalendarDay.date ) } var body: some View { VStack { LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 7), spacing: 20) { ForEach(fetchDatesForMonth(month: month)) { value in let savedDay = days.first(where: { $0.date == value.date }) ZStack { if value.date < getMaxDate() { Button(action: { handleBubbleTap(savedDay, value.date) }){ DayBubbleView(date: value.date, color: getBubbleColor(day: savedDay), opacity: getBubbleOpacity(day: savedDay)) } .buttonStyle(PlainButtonStyle()) } else { Text("") } } .frame(width: 32, height: 32) } } } } func handleBubbleTap(_ savedDay: CalendarDay?, _ date: Date) { if let savedDay = savedDay { onEditTap(savedDay) } else { onCreateTap(date) } } // 保留你原有的fetchDatesForMonth、generateDatesForMonth、getMaxDate等方法 }
额外优化建议
- 移除
CalendarMonthView中不再需要的@State变量(selectedDate、selectedSavedDate、isSheetPresenting),减少不必要的状态管理。 - 确保
CalendarDay类型遵循Identifiable协议(或者为.sheet(item:)提供id参数),否则Sheet可能无法正确识别要展示的编辑项。
内容的提问来源于stack exchange,提问作者McMuellermilch
相关产品推荐
相关产品推荐

